diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index d39aaa65a76c..1ade8027a94a 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -227,6 +227,8 @@ class ASTContext : public RefCountedBase { mutable llvm::FoldingSet DependentAddressSpaceTypes; mutable llvm::FoldingSet DependentPointerTypes; + mutable llvm::FoldingSet + PointerInterpretationTypes; mutable llvm::FoldingSet VectorTypes; mutable llvm::FoldingSet DependentVectorTypes; mutable llvm::FoldingSet MatrixTypes; @@ -1340,19 +1342,42 @@ class ASTContext : public RefCountedBase { /// Get the default pointer interpretation in use. PointerInterpretationKind getDefaultPointerInterpretation() const; + PointerInterpretationKindExplicit + getDefaultPointerInterpretationExplicit() const { + return PointerInterpretationKindExplicit(getDefaultPointerInterpretation(), + /*IsExplicit=*/false); + } + + /// Canonicalise a PointerInterpretationKindExplicit, i.e. turn an explicit + /// default interpretation into an implicit one. Do not use when an explicit + /// default interpretation is meaningful. + PointerInterpretationKindExplicit getCanonicalPointerInterpretationExplicit( + PointerInterpretationKindExplicit PIKE) const { + if (PIKE.IsExplicit) { + if (PIKE.PIK == getDefaultPointerInterpretation()) + return PointerInterpretationKindExplicit(PIKE.PIK, + /*IsExplicit=*/false); + } else { + assert(PIKE.PIK == getDefaultPointerInterpretation() && + "Invalid implicit non-default pointer interpretation"); + } + return PIKE; + } /// Return the uniqued reference to the type for a pointer to /// the specified type. + QualType getPointerType(QualType T, + PointerInterpretationKindExplicit PIKE) const; QualType getPointerType(QualType T) const { - return getPointerType(T, getDefaultPointerInterpretation()); + return getPointerType(T, getDefaultPointerInterpretationExplicit()); } - QualType getPointerType(QualType T, PointerInterpretationKind PIK) const; + // NB: PointerInterpretationKindExplicit-taking variant not present since the + // PIKE may not be canonical, and CanPointerInterpretationKindExplicit + // doesn't exist to ensure the right function is chosen between this and the + // plain QualType version (otherwise this will always be used in preference + // to the QualType one for a CanQualType). CanQualType getPointerType(CanQualType T) const { - return getPointerType(T, getDefaultPointerInterpretation()); - } - CanQualType getPointerType(CanQualType T, - PointerInterpretationKind PIK) const { - return CanQualType::CreateUnsafe(getPointerType((QualType) T, PIK)); + return CanQualType::CreateUnsafe(getPointerType((QualType)T)); } /// Return the uniqued reference to a type adjusted from the original @@ -1436,18 +1461,18 @@ class ASTContext : public RefCountedBase { QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true) const { return getLValueReferenceType(T, SpelledAsLValue, - getDefaultPointerInterpretation()); + getDefaultPointerInterpretationExplicit()); } QualType getLValueReferenceType(QualType T, bool SpelledAsLValue, - PointerInterpretationKind PIK) const; + PointerInterpretationKindExplicit PIKE) const; /// Return the uniqued reference to the type for an rvalue reference /// to the specified type. QualType getRValueReferenceType(QualType T) const { - return getRValueReferenceType(T, getDefaultPointerInterpretation()); + return getRValueReferenceType(T, getDefaultPointerInterpretationExplicit()); } QualType getRValueReferenceType(QualType T, - PointerInterpretationKind PIK) const; + PointerInterpretationKindExplicit PIKE) const; /// Return the uniqued reference to the type for a member pointer to /// the specified type in the specified class. @@ -1457,42 +1482,39 @@ class ASTContext : public RefCountedBase { /// Return a non-unique reference to the type for a variable array of /// the specified element type. - QualType getVariableArrayType(QualType EltTy, Expr *NumElts, - ArrayType::ArraySizeModifier ASM, - unsigned IndexTypeQuals, - SourceRange Brackets, - llvm::Optional - PIK = llvm::None) const; + QualType + getVariableArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals, SourceRange Brackets, + llvm::Optional PIKE = + llvm::None) const; /// Return a non-unique reference to the type for a dependently-sized /// array of the specified element type. /// /// FIXME: We will need these to be uniqued, or at least comparable, at some /// point. - QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts, - ArrayType::ArraySizeModifier ASM, - unsigned IndexTypeQuals, - SourceRange Brackets, - llvm::Optional - PIK = llvm::None) const; + QualType getDependentSizedArrayType( + QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals, SourceRange Brackets, + llvm::Optional PIKE = + llvm::None) const; /// Return a unique reference to the type for an incomplete array of /// the specified element type. - QualType getIncompleteArrayType(QualType EltTy, - ArrayType::ArraySizeModifier ASM, - unsigned IndexTypeQuals, - llvm::Optional - PIK = llvm::None) const; - + QualType getIncompleteArrayType( + QualType EltTy, ArrayType::ArraySizeModifier ASM, unsigned IndexTypeQuals, + llvm::Optional PIKE = + llvm::None) const; /// Return the unique reference to the type for a constant array of /// the specified element type. - QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, - const Expr *SizeExpr, - ArrayType::ArraySizeModifier ASM, - unsigned IndexTypeQuals, - llvm::Optional - PIK = llvm::None) const; + QualType + getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, + const Expr *SizeExpr, ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals, + llvm::Optional PIKE = + llvm::None) const; /// Return a type for a constant array for a string literal of the /// specified element type and length. @@ -1571,6 +1593,11 @@ class ASTContext : public RefCountedBase { PointerInterpretationKind PIK, SourceLocation QualifierLoc) const; + QualType getPointerInterpretationType(PointerInterpretationKind PIK, + SourceRange QualifierRange, + QualType ModifiedType, + QualType EquivalentType) const; + /// Return a K&R style C function type like 'int()'. QualType getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const; @@ -2783,8 +2810,8 @@ class ASTContext : public RefCountedBase { /// /// See C99 6.7.5.3p7 and C99 6.3.2.1p3. QualType getArrayDecayedType(QualType T, - llvm::Optional - PIKFromBase = llvm::None) const; + llvm::Optional + PIKEFromBase = llvm::None) const; /// Return the type that \p PromotableType will promote to: C99 /// 6.3.1.1p2, assuming that \p PromotableType is a promotable integer type. diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 18e7f491f222..6fba8aa48793 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -366,6 +366,12 @@ class ASTNodeTraverser Visit(T->getElementType()); Visit(T->getSizeExpr()); } + void VisitDependentPointerType(const DependentPointerType *T) { + Visit(T->getPointerType()); + } + void VisitPointerInterpretationType(const PointerInterpretationType *T) { + Visit(T->getModifiedType()); + } void VisitVectorType(const VectorType *T) { Visit(T->getElementType()); } void VisitFunctionType(const FunctionType *T) { Visit(T->getReturnType()); } void VisitFunctionProtoType(const FunctionProtoType *T) { diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 99c907582825..5f2108d9cd4f 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -986,9 +986,18 @@ class Expr : public ValueStmt { return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); } + /// Returns the PointerInterpretationKindExplicit for the underlying memory + /// access of this expression, if accessing memory. + llvm::Optional + getUnderlyingPointerInterpretationExplicitOrNone() const; + /// Returns true if the underlying memory of this expression is /// accessed through a capability. - bool hasUnderlyingCapability() const; + bool hasUnderlyingCapability() const { + llvm::Optional PIKE = + getUnderlyingPointerInterpretationExplicitOrNone(); + return PIKE && PIKE->PIK == PIK_Capability; + } /// XXXAR: Expr->getType() returns int for the initializers expression in /// `void x(int& __capability arg) { int& a = arg }` diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index abf1a05c7cd2..2680f9228d70 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -65,7 +65,6 @@ struct PrintingPolicy { SuppressInlineNamespace(true), SuppressInitializers(false), ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), - SuppressCapabilityQualifier(TI && TI->areAllPointersCapabilities()), SuppressTemplateArgsInCXXConstructors(false), SuppressDefaultTemplateArgs(true), Bool(LO.Bool), Nullptr(LO.CPlusPlus11), Restrict(LO.C99), Alignof(LO.CPlusPlus11), @@ -182,9 +181,6 @@ struct PrintingPolicy { /// When true, suppress printing of lifetime qualifier in ARC. unsigned SuppressLifetimeQualifiers : 1; - /// When true, suppress printing of the __capability qualifier. - unsigned SuppressCapabilityQualifier : 1; - /// When true, suppresses printing template arguments in names of C++ /// constructors. unsigned SuppressTemplateArgsInCXXConstructors : 1; diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 58aad72b6a87..e7733b367bce 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -127,6 +127,7 @@ def NestedNameSpecifierKind : EnumPropertyType<"NestedNameSpecifier::SpecifierKind">; def OverloadedOperatorKind : EnumPropertyType; def PointerInterpretationKind : EnumPropertyType; +def PointerInterpretationKindExplicit : PropertyType; def Qualifiers : PropertyType; def QualType : DefaultValuePropertyType; def RefQualifierKind : EnumPropertyType; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 041ee9b61c84..1b8f030e4d8f 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -940,6 +940,9 @@ DEF_TRAVERSE_TYPE(DependentPointerType, { TRY_TO(TraverseType(T->getPointerType())); }) +DEF_TRAVERSE_TYPE(PointerInterpretationType, + { TRY_TO(TraverseType(T->getModifiedType())); }) + DEF_TRAVERSE_TYPE(DependentVectorType, { if (T->getSizeExpr()) TRY_TO(TraverseStmt(T->getSizeExpr())); @@ -1199,6 +1202,9 @@ DEF_TRAVERSE_TYPELOC(DependentPointerType, { TRY_TO(TraverseType(TL.getTypePtr()->getPointerType())); }) +DEF_TRAVERSE_TYPELOC(PointerInterpretationType, + { TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); }) + // FIXME: order? why not size expr first? // FIXME: base VectorTypeLoc is unfinished DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, { diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index ae103d2864bf..5b706542fa5c 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -1480,6 +1481,49 @@ enum PointerInterpretationKind { /// The pointer should always be interpreted as an integer. PIK_Integer, }; +enum { PointerInterpretationKindBits = 1 }; + +/// The interpretation to use for a given pointer, augmented with whether the +/// interpretation is implicit or explicit in the source. +struct PointerInterpretationKindExplicit { + PointerInterpretationKind PIK; + bool IsExplicit; + + PointerInterpretationKindExplicit() = delete; + PointerInterpretationKindExplicit(PointerInterpretationKind PIK, + bool IsExplicit) + : PIK(PIK), IsExplicit(IsExplicit){}; + + bool operator==(PointerInterpretationKindExplicit Other) const { + return PIK == Other.PIK && IsExplicit == Other.IsExplicit; + } + + bool operator!=(PointerInterpretationKindExplicit Other) const { + return !(*this == Other); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(PIK); + ID.AddBoolean(IsExplicit); + } + + enum { PackedBits = PointerInterpretationKindBits + 1 }; + + static PointerInterpretationKindExplicit unpack(unsigned Bits) { + unsigned PIKMask = (1u << PointerInterpretationKindBits) - 1; + unsigned IsExplicitMask = 1u << PointerInterpretationKindBits; + assert((Bits & ~(PIKMask | IsExplicitMask)) == 0 && + "Unknown PIKE bits set!"); + auto PIK = static_cast(Bits & PIKMask); + auto IsExplicit = static_cast(Bits & IsExplicitMask); + return PointerInterpretationKindExplicit(PIK, IsExplicit); + } + + unsigned pack() const { + return static_cast(PIK) | + (static_cast(IsExplicit) << PointerInterpretationKindBits); + } +}; /// The base class of the type hierarchy. /// @@ -1575,18 +1619,19 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { /// Actually an ArrayType::ArraySizeModifier. unsigned SizeModifier : 3; - /// The interpretation (PointerInterpretationKind) to use for this array. - /// For function parameters only. - unsigned PIK : 1; + /// The interpretation (PointerInterpretationKindExplicit) to use for this + /// array. For function parameters only. + unsigned PIKE : PointerInterpretationKindExplicit::PackedBits; /// Whether the pointer interpretation for this array is set. - unsigned HasPIK : 1; + unsigned HasPIKE : 1; }; class ConstantArrayTypeBitfields { friend class ConstantArrayType; - unsigned : NumTypeBits + 3 + 3 + 2; + unsigned : NumTypeBits + 3 + 3 + + PointerInterpretationKindExplicit::PackedBits + 1; /// Whether we have a stored size expression. unsigned HasStoredSizeExpr : 1; @@ -1668,8 +1713,9 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { unsigned : NumTypeBits; - /// The interpretation (PointerInterpretationKind) to use for this pointer. - unsigned PIK : 1; + /// The interpretation (PointerInterpretationKindExplicit) to use for this + /// pointer. + unsigned PIKE : PointerInterpretationKindExplicit::PackedBits; }; class DependentPointerTypeBitfields { @@ -1677,8 +1723,19 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { unsigned : NumTypeBits; - /// The interpretation (PointerInterpretationKind) to use for this pointer. - unsigned PIK : 1; + /// The interpretation (PointerInterpretationKind) to use for this pointer + /// (always explicit). + unsigned PIK : PointerInterpretationKindBits; + }; + + class PointerInterpretationTypeBitfields { + friend class PointerInterpretationType; + + unsigned : NumTypeBits; + + /// The interpretation (PointerInterpretationKind) to use for this pointer + /// (always explicit). + unsigned PIK : PointerInterpretationKindBits; }; class ReferenceTypeBitfields { @@ -1686,9 +1743,9 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { unsigned : NumTypeBits; - /// The interpretation (PointerInterpretationKind) to use for the pointer - /// backing this reference type. - unsigned PIK : 1; + /// The interpretation (PointerInterpretationKindExplicit) to use for the + /// pointer backing this reference type. + unsigned PIKE : PointerInterpretationKindExplicit::PackedBits; /// True if the type was originally spelled with an lvalue sigil. /// This is never true of rvalue references but can also be false @@ -1849,6 +1906,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { ObjCObjectTypeBitfields ObjCObjectTypeBits; PointerTypeBitfields PointerTypeBits; DependentPointerTypeBitfields DependentPointerTypeBits; + PointerInterpretationTypeBitfields PointerInterpretationTypeBits; ReferenceTypeBitfields ReferenceTypeBits; TypeWithKeywordBitfields TypeWithKeywordBits; ElaboratedTypeBitfields ElaboratedTypeBits; @@ -2069,6 +2127,11 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { bool isFunctionNoProtoType() const { return getAs(); } bool isFunctionProtoType() const { return getAs(); } bool isPointerType() const; + + /// Gets the PointerInterpretationKindExplicit for the given type if it can + /// be dereferenced. + llvm::Optional + getPointerInterpretationExplicitOrNone(const ASTContext &Context) const; /// Returns true if this type is a CHERI capability type. /// If \p IncludeIntCap /// is true this also includes __uintcap_t and __intcap_t, otherwise it will @@ -2711,39 +2774,62 @@ class ParenType : public Type, public llvm::FoldingSetNode { static bool classof(const Type *T) { return T->getTypeClass() == Paren; } }; +class IdentityPointerInterpretationTraitFunctor { +public: + template using T = V; + + template + static auto fmap(T &&v, const F &f) + -> T()))>> { + return f(v); + } +}; + /// This class augments a type with a pointer interpretation. -template +template class PointerInterpretationTrait { protected: PointerInterpretationTrait() = default; public: - bool isCHERICapability() const { - return getPointerInterpretation() == PIK_Capability; + typename F::template T isCHERICapability() const { + return F::fmap(getPointerInterpretation(), + [](const auto &PIK) { return PIK == PIK_Capability; }); } - PointerInterpretationKind getPointerInterpretation() const { - return static_cast(this)->getPointerInterpretationImpl(); + typename F::template T + getPointerInterpretation() const { + return F::fmap(getPointerInterpretationExplicit(), + [](const auto &PIKE) { return PIKE.PIK; }); } -}; -/// This class augments a type with an optional pointer interpretation. -template -class OptionalPointerInterpretationTrait { -protected: - OptionalPointerInterpretationTrait() = default; + typename F::template T isPointerInterpretationExplicit() const { + return F::fmap(getPointerInterpretationExplicit(), + [](const auto &PIKE) { return PIKE.IsExplicit; }); + } -public: - bool isCHERICapability() const { - return getPointerInterpretation() == PIK_Capability; + typename F::template T + getPointerInterpretationExplicit() const { + return static_cast(this)->getPointerInterpretationExplicitImpl(); } +}; - llvm::Optional - getPointerInterpretation() const { - return static_cast(this)->getPointerInterpretationImpl(); +class OptionalPointerInterpretationTraitFunctor { +public: + template using T = llvm::Optional; + + template + static auto fmap(T &&v, const F &f) + -> T()))>> { + return v.map(f); } }; +/// This class augments a type with an optional pointer interpretation. +template +using OptionalPointerInterpretationTrait = + PointerInterpretationTrait; + /// PointerType - C99 6.7.5.1 - Pointer Declarators. class PointerType : public Type, public PointerInterpretationTrait, @@ -2754,14 +2840,15 @@ class PointerType : public Type, QualType PointeeType; PointerType(QualType Pointee, QualType CanonicalPtr, - PointerInterpretationKind PIK) + PointerInterpretationKindExplicit PIKE) : Type(Pointer, CanonicalPtr, Pointee->getDependence()), PointeeType(Pointee) { - PointerTypeBits.PIK = PIK; + PointerTypeBits.PIKE = PIKE.pack(); } - PointerInterpretationKind getPointerInterpretationImpl() const { - return static_cast(PointerTypeBits.PIK); + PointerInterpretationKindExplicit + getPointerInterpretationExplicitImpl() const { + return PointerInterpretationKindExplicit::unpack(PointerTypeBits.PIKE); } public: @@ -2771,13 +2858,13 @@ class PointerType : public Type, QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getPointeeType(), getPointerInterpretation()); + Profile(ID, getPointeeType(), getPointerInterpretationExplicit()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, - PointerInterpretationKind PIK) { + PointerInterpretationKindExplicit PIKE) { ID.AddPointer(Pointee.getAsOpaquePtr()); - ID.AddInteger(PIK); + PIKE.Profile(ID); } static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } @@ -2875,16 +2962,17 @@ class ReferenceType : public Type, QualType PointeeType; - PointerInterpretationKind getPointerInterpretationImpl() const { - return static_cast(ReferenceTypeBits.PIK); + PointerInterpretationKindExplicit + getPointerInterpretationExplicitImpl() const { + return PointerInterpretationKindExplicit::unpack(ReferenceTypeBits.PIKE); } protected: ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, - bool SpelledAsLValue, PointerInterpretationKind PIK) + bool SpelledAsLValue, PointerInterpretationKindExplicit PIKE) : Type(tc, CanonicalRef, Referencee->getDependence()), PointeeType(Referencee) { - ReferenceTypeBits.PIK = PIK; + ReferenceTypeBits.PIKE = PIKE.pack(); ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); } @@ -2904,16 +2992,16 @@ class ReferenceType : public Type, } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, PointeeType, isSpelledAsLValue(), getPointerInterpretation()); + Profile(ID, PointeeType, isSpelledAsLValue(), + getPointerInterpretationExplicit()); } - static void Profile(llvm::FoldingSetNodeID &ID, - QualType Referencee, + static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee, bool SpelledAsLValue, - PointerInterpretationKind PIK) { + PointerInterpretationKindExplicit PIKE) { ID.AddPointer(Referencee.getAsOpaquePtr()); ID.AddBoolean(SpelledAsLValue); - ID.AddInteger(PIK); + PIKE.Profile(ID); } static bool classof(const Type *T) { @@ -2927,9 +3015,10 @@ class LValueReferenceType : public ReferenceType { friend class ASTContext; // ASTContext creates these LValueReferenceType(QualType Referencee, QualType CanonicalRef, - bool SpelledAsLValue, PointerInterpretationKind PIK) + bool SpelledAsLValue, + PointerInterpretationKindExplicit PIKE) : ReferenceType(LValueReference, Referencee, CanonicalRef, - SpelledAsLValue, PIK) {} + SpelledAsLValue, PIKE) {} public: bool isSugared() const { return false; } @@ -2945,9 +3034,8 @@ class RValueReferenceType : public ReferenceType { friend class ASTContext; // ASTContext creates these RValueReferenceType(QualType Referencee, QualType CanonicalRef, - PointerInterpretationKind PIK) - : ReferenceType(RValueReference, Referencee, CanonicalRef, false, - PIK) {} + PointerInterpretationKindExplicit PIKE) + : ReferenceType(RValueReference, Referencee, CanonicalRef, false, PIKE) {} public: bool isSugared() const { return false; } @@ -3016,7 +3104,7 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { class ArrayType : public Type, public OptionalPointerInterpretationTrait, public llvm::FoldingSetNode { - friend class OptionalPointerInterpretationTrait; + friend OptionalPointerInterpretationTrait; public: /// Capture whether this is a normal array (e.g. int X[4]) @@ -3031,18 +3119,18 @@ class ArrayType : public Type, /// The element type of the array. QualType ElementType; - llvm::Optional - getPointerInterpretationImpl() const { - if (!ArrayTypeBits.HasPIK) + llvm::Optional + getPointerInterpretationExplicitImpl() const { + if (!ArrayTypeBits.HasPIKE) return llvm::None; - return static_cast(ArrayTypeBits.PIK); + return PointerInterpretationKindExplicit::unpack(ArrayTypeBits.PIKE); } protected: friend class ASTContext; // ASTContext creates these. ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, - unsigned tq, llvm::Optional PIK, + unsigned tq, llvm::Optional PIKE, const Expr *sz = nullptr); public: @@ -3081,8 +3169,8 @@ class ConstantArrayType final ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, const Expr *sz, ArraySizeModifier sm, unsigned tq, - llvm::Optional PIK) - : ArrayType(ConstantArray, et, can, sm, tq, PIK, sz), Size(size) { + llvm::Optional PIKE) + : ArrayType(ConstantArray, et, can, sm, tq, PIKE, sz), Size(size) { ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr; if (ConstantArrayTypeBits.HasStoredSizeExpr) { assert(!can.isNull() && "canonical constant array should not have size"); @@ -3117,14 +3205,14 @@ class ConstantArrayType final void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Ctx, getElementType(), getSize(), getSizeExpr(), getSizeModifier(), getIndexTypeCVRQualifiers(), - getPointerInterpretation()); + getPointerInterpretationExplicit()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx, QualType ET, const llvm::APInt &ArraySize, const Expr *SizeExpr, ArraySizeModifier SizeMod, unsigned TypeQuals, - llvm::Optional PIK); + llvm::Optional PIKE); static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray; @@ -3137,10 +3225,10 @@ class ConstantArrayType final class IncompleteArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. - IncompleteArrayType(QualType et, QualType can, - ArraySizeModifier sm, unsigned tq, - llvm::Optional PIK) - : ArrayType(IncompleteArray, et, can, sm, tq, PIK) {} + IncompleteArrayType(QualType et, QualType can, ArraySizeModifier sm, + unsigned tq, + llvm::Optional PIKE) + : ArrayType(IncompleteArray, et, can, sm, tq, PIKE) {} public: friend class StmtIteratorBase; @@ -3154,18 +3242,18 @@ class IncompleteArrayType : public ArrayType { void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getSizeModifier(), - getIndexTypeCVRQualifiers(), getPointerInterpretation()); + getIndexTypeCVRQualifiers(), getPointerInterpretationExplicit()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals, - llvm::Optional PIK) { + llvm::Optional PIKE) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); - ID.AddBoolean(PIK.hasValue()); - if (PIK.hasValue()) - ID.AddInteger(*PIK); + ID.AddBoolean(PIKE.hasValue()); + if (PIKE.hasValue()) + PIKE->Profile(ID); } }; @@ -3193,12 +3281,11 @@ class VariableArrayType : public ArrayType { /// The range spanned by the left and right array brackets. SourceRange Brackets; - VariableArrayType(QualType et, QualType can, Expr *e, - ArraySizeModifier sm, unsigned tq, - SourceRange brackets, - llvm::Optional PIK) - : ArrayType(VariableArray, et, can, sm, tq, PIK, e), - SizeExpr((Stmt*) e), Brackets(brackets) {} + VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm, + unsigned tq, SourceRange brackets, + llvm::Optional PIKE) + : ArrayType(VariableArray, et, can, sm, tq, PIKE, e), SizeExpr((Stmt *)e), + Brackets(brackets) {} public: friend class StmtIteratorBase; @@ -3253,10 +3340,10 @@ class DependentSizedArrayType : public ArrayType { /// The range spanned by the left and right array brackets. SourceRange Brackets; - DependentSizedArrayType(const ASTContext &Context, QualType et, QualType can, - Expr *e, ArraySizeModifier sm, unsigned tq, - SourceRange brackets, - llvm::Optional PIK); + DependentSizedArrayType( + const ASTContext &Context, QualType et, QualType can, Expr *e, + ArraySizeModifier sm, unsigned tq, SourceRange brackets, + llvm::Optional PIKE); public: friend class StmtIteratorBase; @@ -3279,15 +3366,15 @@ class DependentSizedArrayType : public ArrayType { } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Context, getElementType(), - getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr(), - getPointerInterpretation()); + Profile(ID, Context, getElementType(), getSizeModifier(), + getIndexTypeCVRQualifiers(), getSizeExpr(), + getPointerInterpretationExplicit()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals, Expr *E, - llvm::Optional PIK); + llvm::Optional PIKE); }; /// Represents an extended address space qualifier where the input address space @@ -3347,9 +3434,11 @@ class DependentPointerType : public Type, QualType Canonical, PointerInterpretationKind PIK, SourceLocation Loc); - PointerInterpretationKind getPointerInterpretationImpl() const { - return static_cast( - DependentPointerTypeBits.PIK); + PointerInterpretationKindExplicit + getPointerInterpretationExplicitImpl() const { + PointerInterpretationKind PIK = + static_cast(DependentPointerTypeBits.PIK); + return PointerInterpretationKindExplicit(PIK, /*IsExplicit=*/true); } public: @@ -3371,6 +3460,56 @@ class DependentPointerType : public Type, QualType PointerType, PointerInterpretationKind PIK); }; +class PointerInterpretationType + : public Type, + public PointerInterpretationTrait, + public llvm::FoldingSetNode { + friend class ASTContext; + friend class PointerInterpretationTrait; + + SourceRange Range; + QualType ModifiedType; + QualType EquivalentType; + + PointerInterpretationType(QualType Canonical, PointerInterpretationKind PIK, + SourceRange Range, QualType Modified, + QualType Equivalent) + : Type(PointerInterpretation, Canonical, Equivalent->getDependence()), + Range(Range), ModifiedType(Modified), EquivalentType(Equivalent) { + PointerInterpretationTypeBits.PIK = PIK; + } + + PointerInterpretationKindExplicit + getPointerInterpretationExplicitImpl() const { + PointerInterpretationKind PIK = static_cast( + PointerInterpretationTypeBits.PIK); + return PointerInterpretationKindExplicit(PIK, /*IsExplicit=*/true); + } + +public: + SourceRange getQualifierRange() const { return Range; } + QualType getModifiedType() const { return ModifiedType; } + QualType getEquivalentType() const { return EquivalentType; } + + bool isSugared() const { return true; } + QualType desugar() const { return getEquivalentType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointerInterpretation(), ModifiedType, EquivalentType); + } + + static void Profile(llvm::FoldingSetNodeID &ID, PointerInterpretationKind PIK, + QualType Modified, QualType Equivalent) { + ID.AddInteger(PIK); + ID.AddPointer(Modified.getAsOpaquePtr()); + ID.AddPointer(Equivalent.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == PointerInterpretation; + } +}; + /// Represents an extended vector type where either the type or size is /// dependent. /// diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 31aa8320280f..cf9433148fb9 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -181,6 +181,7 @@ class TypeLoc { /// QualifiedTypeLoc /// AtomicTypeLoc /// AttributedTypeLoc, for those type attributes that behave as qualifiers + /// PointerInterpretationTypeLoc TypeLoc findExplicitQualifierLoc() const; /// Get the typeloc of an AutoType whose type will be deduced for a variable @@ -1790,6 +1791,41 @@ class DependentPointerTypeLoc } }; +struct PointerInterpretationLocInfo { + SourceRange QualifierRange; +}; + +class PointerInterpretationTypeLoc + : public ConcreteTypeLoc { +public: + /// The location of the pointer qualifier, i.e. + /// T __capability + /// ^~~~~~~~~~~~ + SourceRange getQualifierRange() const { + return getLocalData()->QualifierRange; + } + void setQualifierRange(SourceRange Range) { + getLocalData()->QualifierRange = Range; + } + + SourceRange getLocalSourceRange() const { return this->getQualifierRange(); } + + /// The type before the pointer qualifier, i.e. + /// T __capability + /// ^ + QualType getInnerType() const { + return this->getTypePtr()->getModifiedType(); + } + + TypeLoc getModifiedLoc() const { return this->getInnerTypeLoc(); } + + void initializeLocal(ASTContext &Context, SourceRange Range) { + setQualifierRange(Range); + } +}; + //===----------------------------------------------------------------------===// // // All of these need proper implementations. diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 32bb771ee3d6..ad57a14fb79e 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -21,11 +21,17 @@ let Class = PointerType in { def : Property<"pointeeType", QualType> { let Read = [{ node->getPointeeType() }]; } - def : Property<"pointerInterpretation", PointerInterpretationKind> { - let Read = [{ node->getPointerInterpretation() }]; + def : Property<"pik", PointerInterpretationKind> { + let Read = [{ node->getPointerInterpretationExplicit().PIK }]; + } + def : Property<"pikIsExplicit", Bool> { + let Read = [{ node->getPointerInterpretationExplicit().IsExplicit }]; } - def : Creator<[{ return ctx.getPointerType(pointeeType, pointerInterpretation); }]>; + def : Creator<[{ + return ctx.getPointerType( + pointeeType, PointerInterpretationKindExplicit(pik, pikIsExplicit)); + }]>; } let Class = AdjustedType in { @@ -61,8 +67,11 @@ let Class = ReferenceType in { def : Property<"pointeeTypeAsWritten", QualType> { let Read = [{ node->getPointeeTypeAsWritten() }]; } - def : Property<"pointerInterpretation", PointerInterpretationKind> { - let Read = [{ node->getPointerInterpretation() }]; + def : Property<"pik", PointerInterpretationKind> { + let Read = [{ node->getPointerInterpretationExplicit().PIK }]; + } + def : Property<"pikIsExplicit", Bool> { + let Read = [{ node->getPointerInterpretationExplicit().IsExplicit }]; } } @@ -72,16 +81,17 @@ let Class = LValueReferenceType in { } def : Creator<[{ - return ctx.getLValueReferenceType(pointeeTypeAsWritten, - isSpelledAsLValue, - pointerInterpretation); + return ctx.getLValueReferenceType( + pointeeTypeAsWritten, isSpelledAsLValue, + PointerInterpretationKindExplicit(pik, pikIsExplicit)); }]>; } let Class = RValueReferenceType in { def : Creator<[{ - return ctx.getRValueReferenceType(pointeeTypeAsWritten, - pointerInterpretation); + return ctx.getRValueReferenceType( + pointeeTypeAsWritten, + PointerInterpretationKindExplicit(pik, pikIsExplicit)); }]>; } @@ -648,7 +658,7 @@ let Class = DependentPointerType in { def : Property<"pointerType", QualType> { let Read = [{ node->getPointerType() }]; } - def : Property<"pointerInterpretation", PointerInterpretationKind> { + def : Property<"pik", PointerInterpretationKind> { let Read = [{ node->getPointerInterpretation() }]; } def : Property<"qualifierLoc", SourceLocation> { @@ -656,8 +666,32 @@ let Class = DependentPointerType in { } def : Creator<[{ - return ctx.getDependentPointerType(pointerType, pointerInterpretation, - qualifierLoc); + return ctx.getDependentPointerType(pointerType, pik, qualifierLoc); + }]>; +} + +let Class = PointerInterpretationType in { + def : Property<"modifiedType", QualType> { + let Read = [{ node->getModifiedType() }]; + } + def : Property<"equivalentType", QualType> { + let Read = [{ node->getEquivalentType() }]; + } + def : Property<"pik", PointerInterpretationKind> { + let Read = [{ node->getPointerInterpretation() }]; + } + def : Property<"qualifierBeginLoc", SourceLocation> { + let Read = [{ node->getQualifierRange().getBegin() }]; + } + def : Property<"qualifierEndLoc", SourceLocation> { + let Read = [{ node->getQualifierRange().getEnd() }]; + } + + def : Creator<[{ + return ctx.getPointerInterpretationType(pik, + SourceRange(qualifierBeginLoc, + qualifierEndLoc), + modifiedType, equivalentType); }]>; } diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td index 8b1db4bb90cf..f24b8b461095 100644 --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -67,6 +67,7 @@ def DependentSizedArrayType : TypeNode, AlwaysDependent; def DependentSizedExtVectorType : TypeNode, AlwaysDependent; def DependentAddressSpaceType : TypeNode, AlwaysDependent; def DependentPointerType : TypeNode, AlwaysDependent; +def PointerInterpretationType : TypeNode, NeverCanonical; def VectorType : TypeNode; def DependentVectorType : TypeNode, AlwaysDependent; def ExtVectorType : TypeNode; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0381e4d941ea..6dcbfa36acc4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1984,15 +1984,15 @@ class Sema final { const DeclSpec *DS = nullptr); QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA, const DeclSpec *DS = nullptr); - QualType BuildPointerType(QualType T, PointerInterpretationKind PIK, + QualType BuildPointerType(QualType T, PointerInterpretationKindExplicit PIKE, SourceLocation Loc, DeclarationName Entity, - bool* ValidPointer); + bool *ValidPointer); QualType BuildReferenceType(QualType T, bool LValueRef, SourceLocation Loc, DeclarationName Entity); - QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, - Expr *ArraySize, unsigned Quals, - SourceRange Brackets, DeclarationName Entity, - llvm::Optional PIK); + QualType + BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, + unsigned Quals, SourceRange Brackets, DeclarationName Entity, + llvm::Optional PIKE); QualType BuildVectorType(QualType T, Expr *VecSize, SourceLocation AttrLoc); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); @@ -2006,9 +2006,8 @@ class Sema final { QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, SourceLocation AttrLoc); - QualType BuildPointerInterpretationAttr(QualType T, - PointerInterpretationKind PIK, - SourceLocation QualifierLoc); + QualType BuildPointerInterpretationEquivalentType( + QualType T, PointerInterpretationKind PIK, SourceLocation QualifierLoc); bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc); @@ -5052,8 +5051,8 @@ class Sema final { void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ArrayRef Args); - PointerInterpretationKind - PointerInterpretationForBaseExpr(const Expr *Base) const; + PointerInterpretationKindExplicit + PointerInterpretationExplicitForBaseExpr(const Expr *Base) const; void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, @@ -10069,20 +10068,23 @@ class Sema final { void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc); - PointerInterpretationKind PointerInterpretation; - llvm::SmallVector PointerInterpretationStack; + PointerInterpretationKindExplicit CurrentPIKE; + llvm::SmallVector PIKEStack; /// ActOnPragmaPack - Called on well formed \#pragma pack(...). void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *Alignment); - void ActOnPragmaPointerInterpretation(PointerInterpretationKind K); + void + ActOnPragmaPointerInterpretation(PointerInterpretationKindExplicit PIKE) { + CurrentPIKE = PIKE; + } void ActOnPragmaPointerInterpretationPush() { - PointerInterpretationStack.push_back(PointerInterpretation); + PIKEStack.push_back(CurrentPIKE); } void ActOnPragmaPointerInterpretationPop() { - PointerInterpretation = PointerInterpretationStack.back(); - PointerInterpretationStack.pop_back(); + CurrentPIKE = PIKEStack.back(); + PIKEStack.pop_back(); } enum class PragmaAlignPackDiagnoseKind { diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def index 03c6a8f1f448..97577a826cf8 100644 --- a/clang/include/clang/Serialization/TypeBitCodes.def +++ b/clang/include/clang/Serialization/TypeBitCodes.def @@ -66,5 +66,6 @@ TYPE_BIT_CODE(Using, USING, 54) // CHERI extension; leave room for new upstream IDs TYPE_BIT_CODE(DependentPointer, DEPENDENT_POINTER, 80) // 'P' +TYPE_BIT_CODE(PointerInterpretation, POINTER_INTERPRETATION, 81) #undef TYPE_BIT_CODE diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 55475e114df1..824b0fbb2bca 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1300,8 +1300,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, ABI.reset(createCXXABI(Target)); AddrSpaceMap = getAddressSpaceMap(Target, LangOpts); AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts); - PrintingPolicy.SuppressCapabilityQualifier = - Target.areAllPointersCapabilities(); // C99 6.2.5p19. InitBuiltinType(VoidTy, BuiltinType::Void); @@ -1783,7 +1781,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { T = RT->getPointeeType(); else T = getPointerType(RT->getPointeeType(), - RT->getPointerInterpretation()); + RT->getPointerInterpretationExplicit()); } QualType BaseT = getBaseElementType(T); if (T->isFunctionType()) @@ -2436,6 +2434,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { return getTypeInfo( cast(T)->getEquivalentType().getTypePtr()); + case Type::PointerInterpretation: + return getTypeInfo( + cast(T)->getEquivalentType().getTypePtr()); + case Type::Atomic: { // Start with the base type information. TypeInfo Info = getTypeInfo(cast(T)->getValueType()); @@ -3321,27 +3323,33 @@ ASTContext::getDefaultPointerInterpretation() const { /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. -QualType ASTContext::getPointerType(QualType T, PointerInterpretationKind PIK) const { +QualType +ASTContext::getPointerType(QualType T, + PointerInterpretationKindExplicit PIKE) const { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; - PointerType::Profile(ID, T, PIK); + PointerType::Profile(ID, T, PIKE); void *InsertPos = nullptr; if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); + PointerInterpretationKindExplicit CanonicalPIKE = + getCanonicalPointerInterpretationExplicit(PIKE); + // If the pointee type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. + // so fill in the canonical type field. Ditto for the pointer interpretation. QualType Canonical; - if (!T.isCanonical()) { - Canonical = getPointerType(getCanonicalType(T), PIK); + if (!T.isCanonical() || PIKE != CanonicalPIKE) { + Canonical = getPointerType(getCanonicalType(T), + getCanonicalPointerInterpretationExplicit(PIKE)); // Get the new insert position for the node we care about. PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - auto *New = new (*this, TypeAlignment) PointerType(T, Canonical, PIK); + auto *New = new (*this, TypeAlignment) PointerType(T, Canonical, PIKE); Types.push_back(New); PointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -3440,8 +3448,9 @@ QualType ASTContext::getBlockPointerType(QualType T) const { /// getLValueReferenceType - Return the uniqued reference to the type for an /// lvalue reference to the specified type. -QualType -ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue, PointerInterpretationKind PIK) const { +QualType ASTContext::getLValueReferenceType( + QualType T, bool SpelledAsLValue, + PointerInterpretationKindExplicit PIKE) const { assert((!T->isPlaceholderType() || T->isSpecificPlaceholderType(BuiltinType::UnknownAny)) && "Unresolved placeholder type"); @@ -3449,7 +3458,7 @@ ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue, PointerInte // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; - ReferenceType::Profile(ID, T, SpelledAsLValue, PIK); + ReferenceType::Profile(ID, T, SpelledAsLValue, PIKE); void *InsertPos = nullptr; if (LValueReferenceType *RT = @@ -3458,12 +3467,17 @@ ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue, PointerInte const auto *InnerRef = T->getAs(); + PointerInterpretationKindExplicit CanonicalPIKE = + getCanonicalPointerInterpretationExplicit(PIKE); + // If the referencee type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. QualType Canonical; - if (!SpelledAsLValue || InnerRef || !T.isCanonical()) { + if (!SpelledAsLValue || InnerRef || !T.isCanonical() || + PIKE != CanonicalPIKE) { QualType PointeeType = (InnerRef ? InnerRef->getPointeeType() : T); - Canonical = getLValueReferenceType(getCanonicalType(PointeeType), true, PIK); + Canonical = getLValueReferenceType(getCanonicalType(PointeeType), true, + CanonicalPIKE); // Get the new insert position for the node we care about. LValueReferenceType *NewIP = @@ -3471,9 +3485,8 @@ ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue, PointerInte assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - auto *New = new (*this, TypeAlignment) LValueReferenceType(T, Canonical, - SpelledAsLValue, - PIK); + auto *New = new (*this, TypeAlignment) + LValueReferenceType(T, Canonical, SpelledAsLValue, PIKE); Types.push_back(New); LValueReferenceTypes.InsertNode(New, InsertPos); @@ -3482,7 +3495,8 @@ ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue, PointerInte /// getRValueReferenceType - Return the uniqued reference to the type for an /// rvalue reference to the specified type. -QualType ASTContext::getRValueReferenceType(QualType T, PointerInterpretationKind PIK) const { +QualType ASTContext::getRValueReferenceType( + QualType T, PointerInterpretationKindExplicit PIKE) const { assert((!T->isPlaceholderType() || T->isSpecificPlaceholderType(BuiltinType::UnknownAny)) && "Unresolved placeholder type"); @@ -3490,7 +3504,7 @@ QualType ASTContext::getRValueReferenceType(QualType T, PointerInterpretationKin // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; - ReferenceType::Profile(ID, T, false, PIK); + ReferenceType::Profile(ID, T, false, PIKE); void *InsertPos = nullptr; if (RValueReferenceType *RT = @@ -3499,12 +3513,16 @@ QualType ASTContext::getRValueReferenceType(QualType T, PointerInterpretationKin const auto *InnerRef = T->getAs(); + PointerInterpretationKindExplicit CanonicalPIKE = + getCanonicalPointerInterpretationExplicit(PIKE); + // If the referencee type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. QualType Canonical; - if (InnerRef || !T.isCanonical()) { + if (InnerRef || !T.isCanonical() || PIKE != CanonicalPIKE) { QualType PointeeType = (InnerRef ? InnerRef->getPointeeType() : T); - Canonical = getRValueReferenceType(getCanonicalType(PointeeType), PIK); + Canonical = + getRValueReferenceType(getCanonicalType(PointeeType), CanonicalPIKE); // Get the new insert position for the node we care about. RValueReferenceType *NewIP = @@ -3512,8 +3530,8 @@ QualType ASTContext::getRValueReferenceType(QualType T, PointerInterpretationKin assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - auto *New = new (*this, TypeAlignment) RValueReferenceType(T, Canonical, - PIK); + auto *New = + new (*this, TypeAlignment) RValueReferenceType(T, Canonical, PIKE); Types.push_back(New); RValueReferenceTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -3551,13 +3569,10 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const { /// getConstantArrayType - Return the unique reference to the type for an /// array of the specified element type. -QualType ASTContext::getConstantArrayType(QualType EltTy, - const llvm::APInt &ArySizeIn, - const Expr *SizeExpr, - ArrayType::ArraySizeModifier ASM, - unsigned IndexTypeQuals, - llvm::Optional - PIK) const { +QualType ASTContext::getConstantArrayType( + QualType EltTy, const llvm::APInt &ArySizeIn, const Expr *SizeExpr, + ArrayType::ArraySizeModifier ASM, unsigned IndexTypeQuals, + llvm::Optional PIKE) const { assert((EltTy->isDependentType() || EltTy->isIncompleteType() || EltTy->isConstantSizeType()) && "Constant array of VLAs is illegal!"); @@ -3573,21 +3588,27 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, llvm::FoldingSetNodeID ID; ConstantArrayType::Profile(ID, *this, EltTy, ArySize, SizeExpr, ASM, - IndexTypeQuals, PIK); + IndexTypeQuals, PIKE); void *InsertPos = nullptr; if (ConstantArrayType *ATP = ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(ATP, 0); + llvm::Optional CanonicalPIKE = + PIKE.map([this](const auto &PIKE) { + return getCanonicalPointerInterpretationExplicit(PIKE); + }); + // If the element type isn't canonical or has qualifiers, or the array bound // is instantiation-dependent, this won't be a canonical type either, so fill // in the canonical type field. QualType Canon; - if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || SizeExpr) { + if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || SizeExpr || + PIKE != CanonicalPIKE) { SplitQualType canonSplit = getCanonicalType(EltTy).split(); Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize, nullptr, - ASM, IndexTypeQuals, PIK); + ASM, IndexTypeQuals, CanonicalPIKE); Canon = getQualifiedType(Canon, canonSplit.Quals); // Get the new insert position for the node we care about. @@ -3599,9 +3620,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, void *Mem = Allocate( ConstantArrayType::totalSizeToAlloc(SizeExpr ? 1 : 0), TypeAlignment); - auto *New = new (Mem) - ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, IndexTypeQuals, - PIK); + auto *New = new (Mem) ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, + IndexTypeQuals, PIKE); ConstantArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -3751,28 +3771,30 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { /// getVariableArrayType - Returns a non-unique reference to the type for a /// variable array of the specified element type. -QualType ASTContext::getVariableArrayType(QualType EltTy, - Expr *NumElts, - ArrayType::ArraySizeModifier ASM, - unsigned IndexTypeQuals, - SourceRange Brackets, - llvm::Optional - PIK) const { +QualType ASTContext::getVariableArrayType( + QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals, SourceRange Brackets, + llvm::Optional PIKE) const { + llvm::Optional CanonicalPIKE = + PIKE.map([this](const auto &PIKE) { + return getCanonicalPointerInterpretationExplicit(PIKE); + }); + // Since we don't unique expressions, it isn't possible to unique VLA's // that have an expression provided for their size. QualType Canon; // Be sure to pull qualifiers off the element type. - if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { + if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || + PIKE != CanonicalPIKE) { SplitQualType canonSplit = getCanonicalType(EltTy).split(); Canon = getVariableArrayType(QualType(canonSplit.Ty, 0), NumElts, ASM, - IndexTypeQuals, Brackets, PIK); + IndexTypeQuals, Brackets, CanonicalPIKE); Canon = getQualifiedType(Canon, canonSplit.Quals); } - auto *New = new (*this, TypeAlignment) - VariableArrayType(EltTy, Canon, NumElts, ASM, IndexTypeQuals, Brackets, - PIK); + auto *New = new (*this, TypeAlignment) VariableArrayType( + EltTy, Canon, NumElts, ASM, IndexTypeQuals, Brackets, PIKE); VariableArrayTypes.push_back(New); Types.push_back(New); @@ -3782,13 +3804,10 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, /// getDependentSizedArrayType - Returns a non-unique reference to /// the type for a dependently-sized array of the specified element /// type. -QualType ASTContext::getDependentSizedArrayType(QualType elementType, - Expr *numElements, - ArrayType::ArraySizeModifier ASM, - unsigned elementTypeQuals, - SourceRange brackets, - llvm::Optional - PIK) const { +QualType ASTContext::getDependentSizedArrayType( + QualType elementType, Expr *numElements, ArrayType::ArraySizeModifier ASM, + unsigned elementTypeQuals, SourceRange brackets, + llvm::Optional PIKE) const { assert((!numElements || numElements->isTypeDependent() || numElements->isValueDependent()) && "Size must be type- or value-dependent!"); @@ -3798,11 +3817,9 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType, // initializer. We do no canonicalization here at all, which is okay // because they can't be used in most locations. if (!numElements) { - auto *newType - = new (*this, TypeAlignment) - DependentSizedArrayType(*this, elementType, QualType(), - numElements, ASM, elementTypeQuals, - brackets, PIK); + auto *newType = new (*this, TypeAlignment) + DependentSizedArrayType(*this, elementType, QualType(), numElements, + ASM, elementTypeQuals, brackets, PIKE); Types.push_back(newType); return QualType(newType, 0); } @@ -3811,12 +3828,16 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType, // also build a canonical type. SplitQualType canonElementType = getCanonicalType(elementType).split(); + llvm::Optional CanonicalPIKE = + PIKE.map([this](const auto &PIKE) { + return getCanonicalPointerInterpretationExplicit(PIKE); + }); void *insertPos = nullptr; llvm::FoldingSetNodeID ID; - DependentSizedArrayType::Profile(ID, *this, - QualType(canonElementType.Ty, 0), - ASM, elementTypeQuals, numElements, PIK); + DependentSizedArrayType::Profile(ID, *this, QualType(canonElementType.Ty, 0), + ASM, elementTypeQuals, numElements, + CanonicalPIKE); // Look for an existing type with these properties. DependentSizedArrayType *canonTy = @@ -3824,10 +3845,9 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType, // If we don't have one, build one. if (!canonTy) { - canonTy = new (*this, TypeAlignment) - DependentSizedArrayType(*this, QualType(canonElementType.Ty, 0), - QualType(), numElements, ASM, elementTypeQuals, - brackets, PIK); + canonTy = new (*this, TypeAlignment) DependentSizedArrayType( + *this, QualType(canonElementType.Ty, 0), QualType(), numElements, ASM, + elementTypeQuals, brackets, CanonicalPIKE); DependentSizedArrayTypes.InsertNode(canonTy, insertPos); Types.push_back(canonTy); } @@ -3839,41 +3859,45 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType, // If we didn't need extra canonicalization for the element type or the size // expression, then just use that as our result. if (QualType(canonElementType.Ty, 0) == elementType && - canonTy->getSizeExpr() == numElements) + canonTy->getSizeExpr() == numElements && CanonicalPIKE == PIKE) return canon; // Otherwise, we need to build a type which follows the spelling // of the element type. - auto *sugaredType - = new (*this, TypeAlignment) - DependentSizedArrayType(*this, elementType, canon, numElements, - ASM, elementTypeQuals, brackets, PIK); + auto *sugaredType = new (*this, TypeAlignment) + DependentSizedArrayType(*this, elementType, canon, numElements, ASM, + elementTypeQuals, brackets, PIKE); Types.push_back(sugaredType); return QualType(sugaredType, 0); } -QualType ASTContext::getIncompleteArrayType(QualType elementType, - ArrayType::ArraySizeModifier ASM, - unsigned elementTypeQuals, - llvm::Optional - PIK) const { +QualType ASTContext::getIncompleteArrayType( + QualType elementType, ArrayType::ArraySizeModifier ASM, + unsigned elementTypeQuals, + llvm::Optional PIKE) const { llvm::FoldingSetNodeID ID; - IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals, PIK); + IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals, PIKE); void *insertPos = nullptr; if (IncompleteArrayType *iat = IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos)) return QualType(iat, 0); + llvm::Optional CanonicalPIKE = + PIKE.map([this](const auto &PIKE) { + return getCanonicalPointerInterpretationExplicit(PIKE); + }); + // If the element type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. We also have to pull // qualifiers off the element type. QualType canon; - if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) { + if (!elementType.isCanonical() || elementType.hasLocalQualifiers() || + CanonicalPIKE != PIKE) { SplitQualType canonSplit = getCanonicalType(elementType).split(); - canon = getIncompleteArrayType(QualType(canonSplit.Ty, 0), - ASM, elementTypeQuals, PIK); + canon = getIncompleteArrayType(QualType(canonSplit.Ty, 0), ASM, + elementTypeQuals, CanonicalPIKE); canon = getQualifiedType(canon, canonSplit.Quals); // Get the new insert position for the node we care about. @@ -3883,7 +3907,7 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType, } auto *newType = new (*this, TypeAlignment) - IncompleteArrayType(elementType, canon, ASM, elementTypeQuals, PIK); + IncompleteArrayType(elementType, canon, ASM, elementTypeQuals, PIKE); IncompleteArrayTypes.InsertNode(newType, insertPos); Types.push_back(newType); @@ -4337,6 +4361,28 @@ QualType ASTContext::getDependentPointerType(QualType PointerType, return QualType(New, 0); } +QualType ASTContext::getPointerInterpretationType( + PointerInterpretationKind PIK, SourceRange QualifierRange, + QualType ModifiedType, QualType EquivalentType) const { + void *InsertPos = nullptr; + llvm::FoldingSetNodeID ID; + PointerInterpretationType::Profile(ID, PIK, ModifiedType, EquivalentType); + + PointerInterpretationType *Canon = + PointerInterpretationTypes.FindNodeOrInsertPos(ID, InsertPos); + if (Canon) + return QualType(Canon, 0); + + QualType CanonEquivalentType = getCanonicalType(EquivalentType); + Canon = new (*this, TypeAlignment) PointerInterpretationType( + CanonEquivalentType, PIK, QualifierRange, ModifiedType, EquivalentType); + + Types.push_back(Canon); + PointerInterpretationTypes.InsertNode(Canon, InsertPos); + + return QualType(Canon, 0); +} + /// Determine whether \p T is canonical as the result type of a function. static bool isCanonicalResultType(QualType T) { return T.isCanonical() && @@ -6858,7 +6904,8 @@ QualType ASTContext::getExceptionObjectType(QualType T) const { /// /// See C99 6.7.5.3p7 and C99 6.3.2.1p3. QualType ASTContext::getArrayDecayedType( - QualType Ty, llvm::Optional PIKFromBase) const { + QualType Ty, + llvm::Optional PIKEFromBase) const { // Get the element type with 'getAsArrayType' so that we don't lose any // typedefs in the element type of the array. This also handles propagation // of type qualifiers from the array type into the element type if present @@ -6866,17 +6913,16 @@ QualType ASTContext::getArrayDecayedType( const ArrayType *PrettyArrayType = getAsArrayType(Ty); assert(PrettyArrayType && "Not an array type!"); - llvm::Optional PIKFromType = - PrettyArrayType->getPointerInterpretation(); + llvm::Optional PIKEFromType = + PrettyArrayType->getPointerInterpretationExplicit(); - assert((!PIKFromType.hasValue() || !PIKFromBase.hasValue()) && + assert((!PIKEFromType.hasValue() || !PIKEFromBase.hasValue()) && "Cannot have both a qualifier and an interpretation from a base"); - PointerInterpretationKind PIK = - PIKFromType.getValueOr( - PIKFromBase.getValueOr(getDefaultPointerInterpretation())); + PointerInterpretationKindExplicit PIKE = PIKEFromType.getValueOr( + PIKEFromBase.getValueOr(getDefaultPointerInterpretationExplicit())); - QualType PtrTy = getPointerType(PrettyArrayType->getElementType(), PIK); + QualType PtrTy = getPointerType(PrettyArrayType->getElementType(), PIKE); // int x[restrict 4] -> int *restrict QualType Result = getQualifiedType(PtrTy, @@ -8662,7 +8708,9 @@ RecordDecl *ASTContext::getCHERIClassDecl() const { RD = buildImplicitRecord("cheri_object"); RD->startDefinition(); - QualType CapTy = getPointerType(VoidTy, PIK_Capability); + QualType CapTy = getPointerType( + VoidTy, + PointerInterpretationKindExplicit(PIK_Capability, /*IsExplicit=*/true)); QualType FieldTypes[] = { CapTy, CapTy }; static const char *const FieldNames[] = { "co_codecap", "co_datacap" }; @@ -11393,11 +11441,14 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, case 'm': { Qualifiers Qs = Type.getQualifiers(); if (const auto *PT = Type->getAs()) - Type = Context.getPointerType(PT->getPointeeType(), PIK_Capability); + Type = Context.getPointerType(PT->getPointeeType(), + PointerInterpretationKindExplicit( + PIK_Capability, /*IsExplicit=*/true)); else if (const auto *LRT = Type->getAs()) - Type = Context.getLValueReferenceType(LRT->getPointeeTypeAsWritten(), - LRT->isSpelledAsLValue(), - PIK_Capability); + Type = Context.getLValueReferenceType( + LRT->getPointeeTypeAsWritten(), LRT->isSpelledAsLValue(), + PointerInterpretationKindExplicit(PIK_Capability, + /*IsExplicit=*/true)); else { const auto *BT = Type->getAs(); assert(BT && diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index aadf2b9ff3b3..95870207bd69 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -171,6 +171,20 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, QualType(Ty, 0) == Context.getBuiltinMSVaListType()) break; + // Print an a.k.a. clause for a PointerInterpretationType if it's for the + // default pointer interpretation or doesn't modify the interpretation of + // the modified type. + if (const PointerInterpretationType *PIT = + dyn_cast(Ty)) { + if (PIT->getPointerInterpretation() == + Context.getDefaultPointerInterpretation() || + PIT->getModifiedType().getCanonicalType() == + PIT->getEquivalentType().getCanonicalType()) + ShouldAKA = true; + QT = PIT->desugar(); + continue; + } + // Otherwise, do a single-step desugar. QualType Underlying; bool IsSugar = false; @@ -208,23 +222,32 @@ break; \ QT = Underlying; } + auto DesugarPIKE = [&Context](PointerInterpretationKindExplicit PIKE, + bool &ShouldAKA) { + PointerInterpretationKindExplicit CanonPIKE = + Context.getCanonicalPointerInterpretationExplicit(PIKE); + if (PIKE != CanonPIKE) + ShouldAKA = true; + return CanonPIKE; + }; + // If we have a pointer-like type, desugar the pointee as well. // FIXME: Handle other pointer-like types. if (const PointerType *Ty = QT->getAs()) { QT = Context.getPointerType( desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA), - Ty->getPointerInterpretation()); + DesugarPIKE(Ty->getPointerInterpretationExplicit(), ShouldAKA)); } else if (const auto *Ty = QT->getAs()) { QT = Context.getObjCObjectPointerType( desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const LValueReferenceType *Ty = QT->getAs()) { QT = Context.getLValueReferenceType( desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA), true, - Ty->getPointerInterpretation()); + DesugarPIKE(Ty->getPointerInterpretationExplicit(), ShouldAKA)); } else if (const RValueReferenceType *Ty = QT->getAs()) { QT = Context.getRValueReferenceType( desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA), - Ty->getPointerInterpretation()); + DesugarPIKE(Ty->getPointerInterpretationExplicit(), ShouldAKA)); } else if (const auto *Ty = QT->getAs()) { if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) { QualType BaseType = diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 87fe229265d3..0631415215ba 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -344,6 +344,9 @@ namespace clang { ExpectedType VisitVariableArrayType(const VariableArrayType *T); ExpectedType VisitDependentSizedArrayType(const DependentSizedArrayType *T); // FIXME: DependentSizedExtVectorType + ExpectedType VisitDependentPointerType(const DependentPointerType *T); + ExpectedType + VisitPointerInterpretationType(const PointerInterpretationType *T); ExpectedType VisitVectorType(const VectorType *T); ExpectedType VisitExtVectorType(const ExtVectorType *T); ExpectedType VisitFunctionNoProtoType(const FunctionNoProtoType *T); @@ -1119,7 +1122,8 @@ ExpectedType ASTNodeImporter::VisitPointerType(const PointerType *T) { if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); - return Importer.getToContext().getPointerType(*ToPointeeTypeOrErr, T->getPointerInterpretation()); + return Importer.getToContext().getPointerType( + *ToPointeeTypeOrErr, T->getPointerInterpretationExplicit()); } ExpectedType ASTNodeImporter::VisitBlockPointerType(const BlockPointerType *T) { @@ -1138,7 +1142,9 @@ ASTNodeImporter::VisitLValueReferenceType(const LValueReferenceType *T) { if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); - return Importer.getToContext().getLValueReferenceType(*ToPointeeTypeOrErr, T->isSpelledAsLValue(), T->getPointerInterpretation()); + return Importer.getToContext().getLValueReferenceType( + *ToPointeeTypeOrErr, T->isSpelledAsLValue(), + T->getPointerInterpretationExplicit()); } ExpectedType @@ -1148,7 +1154,8 @@ ASTNodeImporter::VisitRValueReferenceType(const RValueReferenceType *T) { if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); - return Importer.getToContext().getRValueReferenceType(*ToPointeeTypeOrErr, T->getPointerInterpretation()); + return Importer.getToContext().getRValueReferenceType( + *ToPointeeTypeOrErr, T->getPointerInterpretationExplicit()); } ExpectedType @@ -1219,6 +1226,38 @@ ExpectedType ASTNodeImporter::VisitDependentSizedArrayType( T->getIndexTypeCVRQualifiers(), ToBracketsRange); } +ExpectedType +ASTNodeImporter::VisitDependentPointerType(const DependentPointerType *T) { + ExpectedType ToPointerTypeOrErr = import(T->getPointerType()); + if (!ToPointerTypeOrErr) + return ToPointerTypeOrErr.takeError(); + Expected ToQualifierLocOrErr = + Importer.Import(T->getQualifierLoc()); + if (!ToQualifierLocOrErr) + return ToQualifierLocOrErr.takeError(); + + return Importer.getToContext().getDependentPointerType( + *ToPointerTypeOrErr, T->getPointerInterpretation(), *ToQualifierLocOrErr); +} + +ExpectedType ASTNodeImporter::VisitPointerInterpretationType( + const PointerInterpretationType *T) { + ExpectedType ToModifiedTypeOrErr = import(T->getModifiedType()); + if (!ToModifiedTypeOrErr) + return ToModifiedTypeOrErr.takeError(); + ExpectedType ToEquivalentTypeOrErr = import(T->getEquivalentType()); + if (!ToEquivalentTypeOrErr) + return ToEquivalentTypeOrErr.takeError(); + Expected ToQualifierRangeOrErr = + Importer.Import(T->getQualifierRange()); + if (!ToQualifierRangeOrErr) + return ToQualifierRangeOrErr.takeError(); + + return Importer.getToContext().getPointerInterpretationType( + T->getPointerInterpretation(), *ToQualifierRangeOrErr, + *ToModifiedTypeOrErr, *ToEquivalentTypeOrErr); +} + ExpectedType ASTNodeImporter::VisitVectorType(const VectorType *T) { ExpectedType ToElementTypeOrErr = import(T->getElementType()); if (!ToElementTypeOrErr) diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 6fcdf7025dd2..4fe984c6ac31 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -823,6 +823,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } + case Type::PointerInterpretation: { + const auto *PointerInterp1 = cast(T1); + const auto *PointerInterp2 = cast(T2); + if (!IsStructurallyEquivalent(Context, PointerInterp1->getModifiedType(), + PointerInterp2->getModifiedType())) + return false; + if (!IsStructurallyEquivalent(Context, PointerInterp1->getEquivalentType(), + PointerInterp2->getEquivalentType())) + return false; + break; + } + case Type::DependentSizedExtVector: { const auto *Vec1 = cast(T1); const auto *Vec2 = cast(T2); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index e171ca3beaf1..75375a8b3d1a 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4966,7 +4966,8 @@ QualType OMPArraySectionExpr::getBaseOriginalType(const Expr *Base) { return OriginalTy; } -bool Expr::hasUnderlyingCapability() const { +llvm::Optional +Expr::getUnderlyingPointerInterpretationExplicitOrNone() const { // This is heavy and the information should instead be recorded on the AST // itself. However this would require large changes and might not be easy to // maintain downstream. We should also try to pass at some point an AST @@ -4981,14 +4982,14 @@ bool Expr::hasUnderlyingCapability() const { } if (E->getValueKind() == VK_PRValue) - return false; + return llvm::None; if (const DeclRefExpr *DRE = dyn_cast(E)) { // XXXAR: or should this be getFoundDecl instead of getDecl? if (const ValueDecl *V = dyn_cast_or_null(DRE->getDecl())) { if (const ReferenceType *RTy = V->getType()->getAs()) { - return RTy->isCHERICapability(); + return RTy->getPointerInterpretationExplicit(); } } } @@ -4998,21 +4999,22 @@ bool Expr::hasUnderlyingCapability() const { NamedDecl *Member = SrcMemb->getMemberDecl(); if (const auto *Value = dyn_cast(Member)) if (auto *Ty = Value->getType()->getAs()) - return Ty->isCHERICapability(); + return Ty->getPointerInterpretationExplicit(); if (isa(Member) && Member->getDeclContext()->isRecord()) - return false; + return llvm::None; if (isa(Member)) { if (SrcMemb->isArrow()) { auto *Base = SrcMemb->getBase()->IgnoreParens(); if (auto *Ty = Base->getType()->getAs()) - return Ty->isCHERICapability(); - return false; + return Ty->getPointerInterpretationExplicit(); + return llvm::None; } - return SrcMemb->getBase()->hasUnderlyingCapability(); + return SrcMemb->getBase() + ->getUnderlyingPointerInterpretationExplicitOrNone(); } - return false; + return llvm::None; } // Handle unary operator. @@ -5020,56 +5022,58 @@ bool Expr::hasUnderlyingCapability() const { if (UO->getOpcode() == UO_Deref) { auto *SubExpr = UO->getSubExpr()->IgnoreParens(); if (auto *Ty = SubExpr->getType()->getAs()) - return Ty->isCHERICapability(); - return false; + return Ty->getPointerInterpretationExplicit(); + return llvm::None; } if (UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec) { - return UO->getSubExpr()->hasUnderlyingCapability(); + return UO->getSubExpr() + ->getUnderlyingPointerInterpretationExplicitOrNone(); } - return false; + return llvm::None; } // Handle array subscript. if (auto SE = dyn_cast(E)) { auto *Base = SE->getBase()->IgnoreParens(); if (auto *Ty = Base->getType()->getAs()) - return Ty->isCHERICapability(); - return Base->hasUnderlyingCapability(); + return Ty->getPointerInterpretationExplicit(); + return Base->getUnderlyingPointerInterpretationExplicitOrNone(); } // Handle casts. if (auto CE = dyn_cast(E)) { if (CE->getCastKind() == CK_LValueBitCast) - return CE->getSubExpr()->hasUnderlyingCapability(); - return false; + return CE->getSubExpr() + ->getUnderlyingPointerInterpretationExplicitOrNone(); + return llvm::None; } // Handle binary operators. if (const BinaryOperator *BO = dyn_cast(E)) { if (BO->isAssignmentOp()) - return BO->getLHS()->hasUnderlyingCapability(); + return BO->getLHS()->getUnderlyingPointerInterpretationExplicitOrNone(); if (BO->getOpcode() == BO_Comma) - return BO->getRHS()->hasUnderlyingCapability(); + return BO->getRHS()->getUnderlyingPointerInterpretationExplicitOrNone(); if (BO->getOpcode() == BO_PtrMemD) { if (BO->getType()->isFunctionType() || BO->hasPlaceholderType(BuiltinType::BoundMember)) - return false; - return BO->getLHS()->hasUnderlyingCapability(); + return llvm::None; + return BO->getLHS()->getUnderlyingPointerInterpretationExplicitOrNone(); } if (BO->getOpcode() == BO_PtrMemI) { if (BO->getType()->isFunctionType() || BO->hasPlaceholderType(BuiltinType::BoundMember)) - return false; + return llvm::None; auto *LHS = BO->getLHS()->IgnoreParens(); if (auto *Ty = LHS->getType()->getAs()) - return Ty->isCHERICapability(); + return Ty->getPointerInterpretationExplicit(); } - return false; + return llvm::None; } // Handle conditional operators. @@ -5077,12 +5081,12 @@ bool Expr::hasUnderlyingCapability() const { auto *True = CO->getTrueExpr()->IgnoreParens(); auto *False = CO->getFalseExpr()->IgnoreParens(); if (True->getType()->isVoidType() || False->getType()->isVoidType()) - return false; - bool CTrue = True->hasUnderlyingCapability(); - bool CFalse = False->hasUnderlyingCapability(); - if (CTrue == CFalse) - return CTrue; - return false; + return llvm::None; + auto CTrue = True->getUnderlyingPointerInterpretationExplicitOrNone(); + auto CFalse = False->getUnderlyingPointerInterpretationExplicitOrNone(); + if (CTrue && CFalse && CTrue->PIK == CFalse->PIK) + return CFalse->IsExplicit ? CFalse : CTrue; + return llvm::None; } if (const CallExpr *CE = dyn_cast(E)) { @@ -5094,7 +5098,7 @@ bool Expr::hasUnderlyingCapability() const { CalleeType = BPT->getPointeeType(); } else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)) { if (isa(Callee->IgnoreParens())) - return false; + return llvm::None; // This should never be overloaded and so should never return null. CalleeType = Expr::findBoundMemberType(Callee); @@ -5102,12 +5106,12 @@ bool Expr::hasUnderlyingCapability() const { const FunctionType *FnType = CalleeType->castAs(); if (auto *Ret = FnType->getReturnType()->getAs()) { - return Ret->isCHERICapability(); + return Ret->getPointerInterpretationExplicit(); } - return false; + return llvm::None; } - return false; + return llvm::None; } QualType Expr::getRealReferenceType(ASTContext &Ctx, @@ -5150,10 +5154,10 @@ QualType Expr::getRealReferenceType(ASTContext &Ctx, isa(E) || isa(E) || isa(E) || isa(E) || isa(E))) { #endif - bool HasCap = Ctx.getTargetInfo().areAllPointersCapabilities() || - E->hasUnderlyingCapability(); - return Ctx.getLValueReferenceType(E->getType(), true, - HasCap ? PIK_Capability : PIK_Integer); + PointerInterpretationKindExplicit PIKE = + E->getUnderlyingPointerInterpretationExplicitOrNone().getValueOr( + Ctx.getDefaultPointerInterpretationExplicit()); + return Ctx.getLValueReferenceType(E->getType(), true, PIKE); } return E->getType(); } diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 91dabf6d7dc6..661b4864c478 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "FormatStringParsing.h" +#include "clang/AST/ASTDiagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Support/ConvertUTF.h" @@ -562,7 +563,9 @@ QualType ArgType::getRepresentativeType(ASTContext &C) const { Res = C.VoidPtrTy; break; case CCapabilityTy: - Res = C.getPointerType(C.VoidTy, PIK_Capability); + Res = + C.getPointerType(C.VoidTy, PointerInterpretationKindExplicit( + PIK_Capability, /*IsExplicit=*/true)); break; case WIntTy: { Res = C.getWIntType(); @@ -576,23 +579,32 @@ QualType ArgType::getRepresentativeType(ASTContext &C) const { } std::string ArgType::getRepresentativeTypeName(ASTContext &C) const { - std::string S = getRepresentativeType(C).getAsString(C.getPrintingPolicy()); + QualType RepTy = getRepresentativeType(C); - std::string Alias; + bool ForceAKA = false; + std::string S = RepTy.getAsString(C.getPrintingPolicy()); if (Name) { + std::string Alias; // Use a specific name for this type, e.g. "size_t". Alias = Name; if (Ptr) { // If ArgType is actually a pointer to T, append an asterisk. Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *"; } - // If Alias is the same as the underlying type, e.g. wchar_t, then drop it. - if (S == Alias) - Alias.clear(); + // If Alias is the same as the underlying type, e.g. wchar_t, then drop it + if (S != Alias) { + S = Alias; + ForceAKA = true; + } } - if (!Alias.empty()) - return std::string("'") + Alias + "' (aka '" + S + "')"; + bool ShouldAKA = false; + QualType DesugaredRepTy = desugarForDiagnostic(C, RepTy, ShouldAKA); + if (ShouldAKA || ForceAKA) { + std::string akaStr = DesugaredRepTy.getAsString(C.getPrintingPolicy()); + if (akaStr != S) + return std::string("'") + S + "' (aka '" + akaStr + "')"; + } return std::string("'") + S + "'"; } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index e85e40c7b932..e42a231a8634 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2252,6 +2252,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::DependentSizedArray: case Type::DependentAddressSpace: case Type::DependentPointer: + case Type::PointerInterpretation: case Type::DependentVector: case Type::DependentSizedExtVector: case Type::Vector: diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index c14a332b6285..77a99d109952 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -377,12 +377,11 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, bool WithGlobalNsPrefix) { // In case of myType* we need to strip the pointer first, fully // qualify and attach the pointer once again. - if (isa(QT.getTypePtr())) { + if (auto *PT = dyn_cast(QT.getTypePtr())) { // Get the qualifiers. Qualifiers Quals = QT.getQualifiers(); QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); - QT = Ctx.getPointerType(QT, QT->isCHERICapabilityType(Ctx) - ? PIK_Capability : PIK_Integer); + QT = Ctx.getPointerType(QT, PT->getPointerInterpretationExplicit()); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, Quals); return QT; @@ -403,17 +402,20 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, // In case of myType& we need to strip the reference first, fully // qualify and attach the reference once again. - if (isa(QT.getTypePtr())) { + if (auto *RT = dyn_cast(QT.getTypePtr())) { // Get the qualifiers. bool IsLValueRefTy = isa(QT.getTypePtr()); Qualifiers Quals = QT.getQualifiers(); QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); // Add the r- or l-value reference type back to the fully // qualified one. + // XXX: Upstream doesn't propagate SpelledAsLValue; should it? if (IsLValueRefTy) - QT = Ctx.getLValueReferenceType(QT); + QT = Ctx.getLValueReferenceType(QT, /*SpelledAsLValue=*/true, + RT->getPointerInterpretationExplicit()); else - QT = Ctx.getRValueReferenceType(QT); + QT = Ctx.getRValueReferenceType(QT, + RT->getPointerInterpretationExplicit()); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, Quals); return QT; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 63433556d933..fb59c6fb52f2 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -118,7 +118,7 @@ bool QualType::isConstant(QualType T, const ASTContext &Ctx) { // value-dependent, ArrayType::ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, unsigned tq, - llvm::Optional PIK, + llvm::Optional PIKE, const Expr *sz) // Note, we need to check for DependentSizedArrayType explicitly here // because we use a DependentSizedArrayType with no size expression as the @@ -139,9 +139,9 @@ ArrayType::ArrayType(TypeClass tc, QualType et, QualType can, ElementType(et) { ArrayTypeBits.IndexTypeQuals = tq; ArrayTypeBits.SizeModifier = sm; - ArrayTypeBits.HasPIK = PIK.hasValue(); - if (PIK.hasValue()) - ArrayTypeBits.PIK = *PIK; + ArrayTypeBits.HasPIKE = PIKE.hasValue(); + if (PIKE.hasValue()) + ArrayTypeBits.PIKE = PIKE->pack(); } unsigned ConstantArrayType::getNumAddressingBits(const ASTContext &Context, @@ -191,12 +191,11 @@ unsigned ConstantArrayType::getMaxSizeBits(const ASTContext &Context) { return Bits; } -void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID, - const ASTContext &Context, QualType ET, - const llvm::APInt &ArraySize, - const Expr *SizeExpr, ArraySizeModifier SizeMod, - unsigned TypeQuals, - llvm::Optional PIK) { +void ConstantArrayType::Profile( + llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, + const llvm::APInt &ArraySize, const Expr *SizeExpr, + ArraySizeModifier SizeMod, unsigned TypeQuals, + llvm::Optional PIKE) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(ArraySize.getZExtValue()); ID.AddInteger(SizeMod); @@ -204,34 +203,29 @@ void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID, ID.AddBoolean(SizeExpr != nullptr); if (SizeExpr) SizeExpr->Profile(ID, Context, true); - ID.AddBoolean(PIK.hasValue()); - if (PIK.hasValue()) - ID.AddInteger(*PIK); -} - -DependentSizedArrayType::DependentSizedArrayType(const ASTContext &Context, - QualType et, QualType can, - Expr *e, ArraySizeModifier sm, - unsigned tq, - SourceRange brackets, - llvm::Optional PIK) - : ArrayType(DependentSizedArray, et, can, sm, tq, PIK, e), - Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) {} - -void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, - const ASTContext &Context, - QualType ET, - ArraySizeModifier SizeMod, - unsigned TypeQuals, - Expr *E, - llvm::Optional PIK) { + ID.AddBoolean(PIKE.hasValue()); + if (PIKE.hasValue()) + PIKE->Profile(ID); +} + +DependentSizedArrayType::DependentSizedArrayType( + const ASTContext &Context, QualType et, QualType can, Expr *e, + ArraySizeModifier sm, unsigned tq, SourceRange brackets, + llvm::Optional PIKE) + : ArrayType(DependentSizedArray, et, can, sm, tq, PIKE, e), + Context(Context), SizeExpr((Stmt *)e), Brackets(brackets) {} + +void DependentSizedArrayType::Profile( + llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, + ArraySizeModifier SizeMod, unsigned TypeQuals, Expr *E, + llvm::Optional PIKE) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); E->Profile(ID, Context, true); - ID.AddBoolean(PIK.hasValue()); - if (PIK.hasValue()) - ID.AddInteger(*PIK); + ID.AddBoolean(PIKE.hasValue()); + if (PIKE.hasValue()) + PIKE->Profile(ID); } DependentVectorType::DependentVectorType(const ASTContext &Context, @@ -621,32 +615,46 @@ bool Type::isStructureOrClassType() const { return false; } -bool Type::isCHERICapabilityType(const ASTContext &Context, - bool IncludeIntCap) const { +llvm::Optional +Type::getPointerInterpretationExplicitOrNone(const ASTContext &Context) const { + // NB: PointerInterpretationType must come first as it's sugar that getAs + // will otherwise strip, forgetting IsExplicit. + if (const PointerInterpretationType *PIT = getAs()) + return PIT->getPointerInterpretationExplicit(); + if (const PointerType *PT = getAs()) - return PT->isCHERICapability(); - else if (const ReferenceType *RT = getAs()) - return RT->isCHERICapability(); - else if (isObjCObjectPointerType() || isBlockPointerType()) - return Context.getTargetInfo().areAllPointersCapabilities(); - else if (const EnumType *ET = getAs()) { - QualType Ty = ET->getDecl()->getIntegerType(); - return Ty.isNull() ? false - : Ty->isCHERICapabilityType(Context, IncludeIntCap); - } else if (const BuiltinType *BT = getAs()) { - auto Kind = BT->getKind(); - if (Kind == BuiltinType::IntCap || - Kind == BuiltinType::UIntCap) - return IncludeIntCap; - if (Kind == BuiltinType::ObjCId || Kind == BuiltinType::NullPtr) - return Context.getTargetInfo().areAllPointersCapabilities(); - } else if (const AtomicType *AT = getAs()) - return AT->getValueType()->isCHERICapabilityType(Context, IncludeIntCap); - else if (const MemberPointerType *MPT = getAs()) + return PT->getPointerInterpretationExplicit(); + if (const ReferenceType *RT = getAs()) + return RT->getPointerInterpretationExplicit(); + if (isObjCObjectPointerType() || isBlockPointerType()) + return Context.getDefaultPointerInterpretationExplicit(); + if (const ArrayType *AT = getAsArrayTypeUnsafe()) + return AT->getPointerInterpretationExplicit(); + if (const DependentPointerType *DPT = getAs()) + return DPT->getPointerInterpretationExplicit(); + if (const AtomicType *AT = getAs()) + return AT->getValueType()->getPointerInterpretationExplicitOrNone(Context); + if (const BuiltinType *BT = getAs()) { + if (BT->getKind() == BuiltinType::ObjCId || + BT->getKind() == BuiltinType::NullPtr) + return Context.getDefaultPointerInterpretationExplicit(); + } + if (const MemberPointerType *MPT = getAs()) { // XXXAR: Currently member function pointers contain capabities, but // pointers to member data don't - return Context.getTargetInfo().areAllPointersCapabilities() && MPT->isMemberFunctionPointer(); - return false; + if (MPT->isMemberFunctionPointer()) + return Context.getDefaultPointerInterpretationExplicit(); + } + return llvm::None; +} + +bool Type::isCHERICapabilityType(const ASTContext &Context, + bool IncludeIntCap) const { + llvm::Optional PIKE = + getPointerInterpretationExplicitOrNone(Context); + if (PIKE) + return PIKE->PIK == PIK_Capability; + return IncludeIntCap && isIntCapType(); } bool Type::isIntCapType() const { @@ -1015,7 +1023,8 @@ struct SimpleTransformVisitor : public TypeVisitor { if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) return QualType(T, 0); - return Ctx.getPointerType(pointeeType, T->getPointerInterpretation()); + return Ctx.getPointerType(pointeeType, + T->getPointerInterpretationExplicit()); } QualType VisitBlockPointerType(const BlockPointerType *T) { @@ -1039,7 +1048,7 @@ struct SimpleTransformVisitor : public TypeVisitor { return QualType(T, 0); return Ctx.getLValueReferenceType(pointeeType, T->isSpelledAsLValue(), - T->getPointerInterpretation()); + T->getPointerInterpretationExplicit()); } QualType VisitRValueReferenceType(const RValueReferenceType *T) { @@ -1052,7 +1061,7 @@ struct SimpleTransformVisitor : public TypeVisitor { return QualType(T, 0); return Ctx.getRValueReferenceType(pointeeType, - T->getPointerInterpretation()); + T->getPointerInterpretationExplicit()); } QualType VisitMemberPointerType(const MemberPointerType *T) { @@ -1252,6 +1261,26 @@ struct SimpleTransformVisitor : public TypeVisitor { // FIXME: Non-trivial to implement, but important for C++ SUGARED_TYPE_CLASS(Elaborated) + QualType VisitPointerInterpretationType(const PointerInterpretationType *T) { + QualType modifiedType = recurse(T->getModifiedType()); + if (modifiedType.isNull()) + return {}; + + QualType equivalentType = recurse(T->getEquivalentType()); + if (equivalentType.isNull()) + return {}; + + if (modifiedType.getAsOpaquePtr() == + T->getModifiedType().getAsOpaquePtr() && + equivalentType.getAsOpaquePtr() == + T->getEquivalentType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getPointerInterpretationType(T->getPointerInterpretation(), + T->getQualifierRange(), + modifiedType, equivalentType); + } + QualType VisitAttributedType(const AttributedType *T) { QualType modifiedType = recurse(T->getModifiedType()); if (modifiedType.isNull()) @@ -1984,6 +2013,10 @@ namespace { return Visit(T->getModifiedType()); } + Type *VisitPointerInterpretationType(const PointerInterpretationType *T) { + return Visit(T->getModifiedType()); + } + Type *VisitMacroQualifiedType(const MacroQualifiedType *T) { return Visit(T->getUnderlyingType()); } diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index c7dc31422195..765d85b46106 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -685,6 +685,10 @@ namespace { return Visit(T.getModifiedLoc()); } + TypeLoc VisitPointerInterpretationTypeLoc(PointerInterpretationTypeLoc T) { + return Visit(T.getModifiedLoc()); + } + TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) { return Visit(T.getInnerLoc()); } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 6bff3bc29d2c..3312c51b0766 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -99,11 +99,29 @@ namespace { } }; + class PointerInterpretationRAII { + SmallVectorImpl &PointerInterpretations; + + public: + explicit PointerInterpretationRAII( + SmallVectorImpl &PointerInterpretations, + PointerInterpretationKind PointerInterpretation) + : PointerInterpretations(PointerInterpretations) { + PointerInterpretations.push_back(PointerInterpretation); + } + + ~PointerInterpretationRAII() { + assert(PointerInterpretations.empty() && + "Unhandled pointer interpretations"); + } + }; + class TypePrinter { PrintingPolicy Policy; unsigned Indentation; bool HasEmptyPlaceHolder = false; bool InsideCCAttribute = false; + SmallVector PointerInterpretations; public: explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0) @@ -263,6 +281,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::MemberPointer: case Type::DependentAddressSpace: case Type::DependentPointer: + case Type::PointerInterpretation: case Type::DependentVector: case Type::DependentSizedExtVector: case Type::Vector: @@ -304,6 +323,10 @@ void TypePrinter::printBefore(QualType T, raw_ostream &OS) { /// Prints the part of the type string before an identifier, e.g. for /// "int foo[10]" it prints "int ". void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) { + SmallVector ThisPointerInterpretations = + PointerInterpretations; + PointerInterpretations.clear(); + if (Policy.SuppressSpecifiers && T->isSpecifierType()) return; @@ -340,22 +363,29 @@ void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) { } // Print __capability - if (!Policy.SuppressCapabilityQualifier) { - if (const PointerType *PTy = dyn_cast(T)) { - if (PTy->getPointerInterpretation() == PIK_Capability) { - OS << " __capability"; - if (hasAfterQuals || !PrevPHIsEmpty.get()) - OS << " "; - } - } - else if (const ReferenceType *RTy = dyn_cast(T)) { - if (RTy->getPointerInterpretation() == PIK_Capability) { - OS << " __capability"; - if (hasAfterQuals || !PrevPHIsEmpty.get()) - OS << " "; - } + llvm::Optional PIKE; + if (const PointerType *PTy = dyn_cast(T)) + PIKE = PTy->getPointerInterpretationExplicit(); + else if (const ReferenceType *RTy = dyn_cast(T)) + PIKE = RTy->getPointerInterpretationExplicit(); + + if (PIKE && PIKE->IsExplicit) + ThisPointerInterpretations.push_back(PIKE->PIK); + + bool appendSpaceAfterPIKs = false; + for (const auto PIK : llvm::reverse(ThisPointerInterpretations)) { + switch (PIK) { + case PIK_Capability: + OS << " __capability"; + break; + default: + llvm_unreachable("Unsupported pointer interpretation"); } + if (hasAfterQuals || !PrevPHIsEmpty.get()) + appendSpaceAfterPIKs = true; } + if (appendSpaceAfterPIKs) + OS << " "; if (hasAfterQuals) { if (NeedARCStrongQualifier) { @@ -633,19 +663,28 @@ void TypePrinter::printDependentAddressSpaceAfter( void TypePrinter::printDependentPointerBefore( const DependentPointerType *T, raw_ostream &OS) { + PointerInterpretationRAII PI(PointerInterpretations, + T->getPointerInterpretation()); printBefore(T->getPointerType(), OS); } void TypePrinter::printDependentPointerAfter( const DependentPointerType *T, raw_ostream &OS) { - if (!Policy.SuppressCapabilityQualifier) { - if (T->getPointerInterpretation() == PIK_Capability) { - OS << " __capability"; - } - } printAfter(T->getPointerType(), OS); } +void TypePrinter::printPointerInterpretationBefore( + const PointerInterpretationType *T, raw_ostream &OS) { + PointerInterpretationRAII PI(PointerInterpretations, + T->getPointerInterpretation()); + printBefore(T->getModifiedType(), OS); +} + +void TypePrinter::printPointerInterpretationAfter( + const PointerInterpretationType *T, raw_ostream &OS) { + printAfter(T->getModifiedType(), OS); +} + void TypePrinter::printDependentSizedExtVectorBefore( const DependentSizedExtVectorType *T, raw_ostream &OS) { diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index a9631a27e4df..1d9099b509d1 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -807,9 +807,9 @@ AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args, int64_t SizeInBits = CGF.getContext().toBits(SizeInChars); llvm::Type *ValLLVMTy; if (ValTy->isCHERICapabilityType(CGF.getContext())) { - ValTy = - CGF.getContext().getPointerType(CGF.getContext().VoidTy, - PIK_Capability); + PointerInterpretationKindExplicit PIKE(PIK_Capability, + /*IsExplicit=*/true); + ValTy = CGF.getContext().getPointerType(CGF.getContext().VoidTy, PIKE); ValLLVMTy = CGF.Int8CheriCapTy; } else { ValTy = diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 12fda838ffd0..c695a675b19e 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3358,6 +3358,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { case Type::Attributed: T = cast(T)->getEquivalentType(); break; + case Type::PointerInterpretation: + T = cast(T)->getEquivalentType(); + break; case Type::Elaborated: T = cast(T)->getNamedType(); break; @@ -3552,6 +3555,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit, case Type::Auto: case Type::Attributed: + case Type::PointerInterpretation: case Type::Adjusted: case Type::Decayed: case Type::DeducedTemplateSpecialization: diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index ebfb5f25b3d6..31d59be84427 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2345,6 +2345,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { case Type::TypeOf: case Type::UnaryTransform: case Type::Attributed: + case Type::PointerInterpretation: case Type::SubstTemplateTypeParm: case Type::MacroQualified: // Keep walking after single level desugaring. diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 916dba067b1f..5daaed93b36b 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -3560,19 +3560,23 @@ void PragmaPointerInterpretation::HandlePragma(Preprocessor &PP, else if (Interpretation->getName() == "pop") Actions.ActOnPragmaPointerInterpretationPop(); else { - PointerInterpretationKind PIK = - llvm::StringSwitch(Interpretation->getName()) - .Case("capability", PointerInterpretationKind::PIK_Capability) - .Case("integer", PointerInterpretationKind::PIK_Integer) - .Case("default", Actions.Context.getDefaultPointerInterpretation()) - .Default((PointerInterpretationKind)-1); - if (PIK == (PointerInterpretationKind)-1) { + llvm::Optional PIKE = + llvm::StringSwitch>( + Interpretation->getName()) + .Case("capability", PointerInterpretationKindExplicit( + PIK_Capability, /*IsExplicit=*/true)) + .Case("integer", PointerInterpretationKindExplicit( + PIK_Integer, /*IsExplicit=*/true)) + .Case("default", + Actions.Context.getDefaultPointerInterpretationExplicit()) + .Default(llvm::None); + if (!PIKE) { PP.Diag(Tok.getLocation(), diag::err_pragma_pointer_interpretation_invalid_argument) << PP.getSpelling(Tok); return; } - Actions.ActOnPragmaPointerInterpretation(PIK); + Actions.ActOnPragmaPointerInterpretation(*PIKE); } PP.Lex(Tok); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index ea1ce990779a..d739a5b7b7d3 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -211,8 +211,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this), - ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr), - CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) { + ThreadSafetyDeclCache(nullptr), + CurrentPIKE(Context.getDefaultPointerInterpretationExplicit()), + VarDataSharingAttributesStack(nullptr), CurScope(nullptr), + Ident_super(nullptr), Ident___float128(nullptr) { assert(pp.TUKind == TUKind); TUScope = nullptr; isConstantEvaluatedOverride = false; @@ -237,8 +239,6 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, // Initialization of data sharing attributes stack for OpenMP InitDataSharingAttributesStack(); - PointerInterpretation = Context.getDefaultPointerInterpretation(); - std::unique_ptr Callbacks = std::make_unique(); SemaPPCallbackHandler = Callbacks.get(); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 75de73455cf4..b69492768848 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -384,10 +384,6 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, AlignPackStack.Act(PragmaLoc, Action, SlotLabel, Info); } -void Sema::ActOnPragmaPointerInterpretation(PointerInterpretationKind K) { - PointerInterpretation = K; -} - void Sema::DiagnoseNonDefaultPragmaAlignPack(PragmaAlignPackDiagnoseKind Kind, SourceLocation IncludeLoc) { if (Kind == PragmaAlignPackDiagnoseKind::NonDefaultStateAtInclude) { diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 7e7008fb6c3b..69eca8accb7f 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -3799,10 +3799,9 @@ bool Sema::CheckCHERIAssignCompatible(QualType LHS, QualType RHS, if (InsertBitCast) { // Insert a CK_BitCast to ensure we don't crash during codegen (see // https://github.com/CTSRD-CHERI/clang/issues/178) - bool RHSIsCap = RHS->isCHERICapabilityType(Context, false); QualType BitCastTy = Context.getPointerType( LHS->getAs()->getPointeeType(), - RHSIsCap ? PIK_Capability : PIK_Integer); + RHS->getAs()->getPointerInterpretationExplicit()); RHSExpr = ImplicitCastExpr::Create(Context, BitCastTy, CK_BitCast, RHSExpr, nullptr, VK_PRValue, CurFPFeatureOverrides()); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 63f42212c861..86ab24f1e9a0 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -195,9 +195,9 @@ static bool checkCapArg(Sema &S, CallExpr *TheCall, unsigned ArgIndex, // Treat NULL/nullptr/__null/literal 0 as void * __capability. if (!SrcTy->isCapabilityPointerType() && Source->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull)) - SrcTy = Ctx.getPointerType(SrcTy->isPointerType() ? SrcTy->getPointeeType() - : Ctx.VoidTy, - PIK_Capability); + SrcTy = Ctx.getPointerType( + SrcTy->isPointerType() ? SrcTy->getPointeeType() : Ctx.VoidTy, + PointerInterpretationKindExplicit(PIK_Capability, /*IsExplicit=*/true)); if (ResultingSrcTy) *ResultingSrcTy = SrcTy; if (!SrcTy->isCapabilityPointerType() && !SrcTy->isIntCapType()) { @@ -2228,8 +2228,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, ResultPointeeTy.addVolatile(); if (SrcTy->getPointeeType().isConstQualified()) ResultPointeeTy.addConst(); - TheCall->setType( - Context.getPointerType(ResultPointeeTy, PIK_Capability)); + llvm::Optional PIKE = + SrcTy->getPointerInterpretationExplicitOrNone(Context); + assert(PIKE && "Pointer must have interpretation"); + assert(PIKE->PIK == PIK_Capability && + "Capability must have capability interpretation"); + TheCall->setType(Context.getPointerType(ResultPointeeTy, *PIKE)); } break; } @@ -2265,8 +2269,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); } // Result is always void * __capability - TheCall->setType( - Context.getPointerType(Context.VoidTy, PIK_Capability)); + PointerInterpretationKindExplicit PIKE(PIK_Capability, /*IsExplicit=*/true); + TheCall->setType(Context.getPointerType(Context.VoidTy, PIKE)); break; } case Builtin::BI__builtin_cheri_tag_clear: @@ -2320,8 +2324,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, checkCapArg(*this, TheCall, 1, &SrcTy)) return ExprError(); if (SrcTy->isPointerType()) { - TheCall->setType(Context.getPointerType(SrcTy->getPointeeType(), - PIK_Integer)); + PointerInterpretationKindExplicit PIKE(PIK_Integer, /*IsExplicit=*/true); + TheCall->setType(Context.getPointerType(SrcTy->getPointeeType(), PIKE)); } else { assert(SrcTy->isIntCapType()); TheCall->setType(SrcTy->isSignedIntegerType() ? Context.getIntPtrType() @@ -2355,8 +2359,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); } } - TheCall->setType( - Context.getPointerType(ResultPointee, PIK_Capability)); + PointerInterpretationKindExplicit PIKE(PIK_Capability, /*IsExplicit=*/true); + TheCall->setType(Context.getPointerType(ResultPointee, PIKE)); break; } case Builtin::BI__builtin_cheri_perms_check: diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0ed8dea52d00..657c3a537247 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9665,16 +9665,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, ArrayRef OldParams = FPT->getParamTypes(); llvm::SmallVector NewParams; for (QualType T : OldParams) { - if (const PointerType *PT = T->getAs()) - NewParams.push_back(Context.getPointerType(PT->getPointeeType(), - PIK_Capability)); - else - NewParams.push_back(T); + QualType NewT; + if (T->isPointerType() || T->isReferenceType() || T->isArrayType()) + NewT = BuildPointerInterpretationEquivalentType(T, PIK_Capability, + SourceLocation()); + NewParams.push_back(NewT); } QualType RetTy = FPT->getReturnType(); - if (const PointerType *PT = RetTy->getAs()) - RetTy = Context.getPointerType(PT->getPointeeType(), - PIK_Capability); + if (RetTy->isPointerType() || RetTy->isReferenceType() || + RetTy->isArrayType()) + RetTy = BuildPointerInterpretationEquivalentType(RetTy, PIK_Capability, + SourceLocation()); NewFD->setType(Context.getFunctionType(RetTy, NewParams, FPT->getExtProtoInfo())); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d2d578f4ef2a..c8c6fa397e91 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -139,8 +139,8 @@ static bool hasAnyExplicitStorageClass(const FunctionDecl *D) { return false; } -PointerInterpretationKind -Sema::PointerInterpretationForBaseExpr(const Expr *Base) const { +PointerInterpretationKindExplicit +Sema::PointerInterpretationExplicitForBaseExpr(const Expr *Base) const { QualType DerefType; while (Base) { @@ -175,13 +175,12 @@ Sema::PointerInterpretationForBaseExpr(const Expr *Base) const { // following should be an error in the hybrid ABI: // void * __capability b; // void *__capability *__capability c = &b; - if (!DerefType.getTypePtrOrNull()) - return Context.getDefaultPointerInterpretation(); - // If the basetype is __uintcap_t we don't want to treat the result as a - // capability (such as in uintcap_t foo; return &foo;) - if (DerefType->isCHERICapabilityType(Context, /*IncludeIntCap=*/false)) - return PIK_Capability; - return Context.getDefaultPointerInterpretation(); + if (DerefType.isNull()) + return Context.getDefaultPointerInterpretationExplicit(); + llvm::Optional PIKE = + DerefType->getPointerInterpretationExplicitOrNone(Context); + assert(PIKE && "Dereferenced type must have a pointer interpretation"); + return *PIKE; } /// Check whether we're in an extern inline function and referring to a @@ -572,9 +571,10 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) { // T" can be converted to an rvalue of type "pointer to T". // if (getLangOpts().C99 || getLangOpts().CPlusPlus || E->isLValue()) { - PointerInterpretationKind PIK = PointerInterpretationForBaseExpr(E); + PointerInterpretationKindExplicit PIKE = + PointerInterpretationExplicitForBaseExpr(E); ExprResult Res = ImpCastExprToType( - E, Context.getArrayDecayedType(Ty, PIK), CK_ArrayToPointerDecay); + E, Context.getArrayDecayedType(Ty, PIKE), CK_ArrayToPointerDecay); if (Res.isInvalid()) return ExprError(); E = Res.get(); @@ -2999,8 +2999,8 @@ Sema::PerformObjectMemberConversion(Expr *From, : FromType.getAddressSpace()); if (FromPtrType) { - DestType = Context.getPointerType(DestRecordType, - FromPtrType->getPointerInterpretation()); + DestType = Context.getPointerType( + DestRecordType, FromPtrType->getPointerInterpretationExplicit()); FromRecordType = FromPtrType->getPointeeType(); PointerConversions = true; } else { @@ -3085,10 +3085,11 @@ Sema::PerformObjectMemberConversion(Expr *From, FromLoc, FromRange, &BasePath)) return ExprError(); - if (PointerConversions) - QType = Context.getPointerType(QType, - FromType->isCHERICapabilityType(Context) - ? PIK_Capability : PIK_Integer); + if (PointerConversions) { + PointerInterpretationKindExplicit PIKE = + FromType->getAs()->getPointerInterpretationExplicit(); + QType = Context.getPointerType(QType, PIKE); + } From = ImpCastExprToType(From, QType, CK_UncheckedDerivedToBase, VK, &BasePath).get(); @@ -4491,6 +4492,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::TypeOf: case Type::UnaryTransform: case Type::Attributed: + case Type::PointerInterpretation: case Type::SubstTemplateTypeParm: case Type::MacroQualified: // Keep walking after single level desugaring. @@ -8053,10 +8055,17 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, } // Get the pointer interpretation. - PointerInterpretationKind PIK = S.Context.getDefaultPointerInterpretation(); - if (LHSTy->isCHERICapabilityType(S.Context, false) || - RHSTy->isCHERICapabilityType(S.Context, false)) - PIK = PIK_Capability; + llvm::Optional LHSPIKE = + LHSTy->getPointerInterpretationExplicitOrNone(S.Context); + llvm::Optional RHSPIKE = + RHSTy->getPointerInterpretationExplicitOrNone(S.Context); + assert(LHSPIKE && "LHS pointer must have an interpretation"); + assert(RHSPIKE && "RHS pointer must have an interpretation"); + PointerInterpretationKindExplicit PIKE = *LHSPIKE; + // Prefer capability to integer, explicit to implicit + if (RHSPIKE->PIK == PIK_Capability && + (LHSPIKE->PIK == PIK_Integer || !LHSPIKE->IsExplicit)) + PIKE = *RHSPIKE; // C99 6.5.15p6: If both operands are pointers to compatible types or to // differently qualified versions of compatible types, the result type is @@ -8120,7 +8129,8 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, // to get a consistent AST. QualType incompatTy; incompatTy = S.Context.getPointerType( - S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace), PIK); + S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace), + PIKE); LHS = S.ImpCastExprToType(LHS.get(), incompatTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), incompatTy, RHSCastKind); @@ -8159,7 +8169,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, if (IsBlockPointer) ResultTy = S.Context.getBlockPointerType(ResultTy); else - ResultTy = S.Context.getPointerType(ResultTy, PIK); + ResultTy = S.Context.getPointerType(ResultTy, PIKE); LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind); @@ -8210,7 +8220,8 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS, QualType destPointee = S.Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = S.Context.getPointerType( - destPointee, RHSTy->castAs()->getPointerInterpretation()); + destPointee, + RHSTy->castAs()->getPointerInterpretationExplicit()); // Add qualifiers if necessary. LHS = S.ImpCastExprToType(LHS.get(), destType, CK_NoOp); // Promote to void*. @@ -8221,7 +8232,8 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS, QualType destPointee = S.Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = S.Context.getPointerType( - destPointee, LHSTy->castAs()->getPointerInterpretation()); + destPointee, + LHSTy->castAs()->getPointerInterpretationExplicit()); // Add qualifiers if necessary. RHS = S.ImpCastExprToType(RHS.get(), destType, CK_NoOp); // Promote to void*. @@ -14086,8 +14098,9 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { CheckAddressOfPackedMember(op); - PointerInterpretationKind PIK = PointerInterpretationForBaseExpr(op); - return Context.getPointerType(op->getType(), PIK); + PointerInterpretationKindExplicit PIKE = + PointerInterpretationExplicitForBaseExpr(op); + return Context.getPointerType(op->getType(), PIKE); } static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c29e39e4b9f4..3f23cafc58dd 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4237,8 +4237,9 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } case ICK_Array_To_Pointer: { - PointerInterpretationKind PIK = PointerInterpretationForBaseExpr(From); - FromType = Context.getArrayDecayedType(FromType, PIK); + PointerInterpretationKindExplicit PIKE = + PointerInterpretationExplicitForBaseExpr(From); + FromType = Context.getArrayDecayedType(FromType, PIKE); From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, VK_PRValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -6636,18 +6637,21 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, /// The class for a pointer-to-member; a constant array type with a bound /// (if any) for an array. const Type *ClassOrBound; - llvm::Optional PIK; + llvm::Optional PIKE; Step(Kind K, const Type *ClassOrBound = nullptr, - llvm::Optional PIK = llvm::None) - : K(K), ClassOrBound(ClassOrBound), PIK(PIK) {} + llvm::Optional PIKE = llvm::None) + : K(K), ClassOrBound(ClassOrBound), PIKE(PIKE) {} + + Step(Kind K, PointerInterpretationKindExplicit PIKE) + : Step(K, nullptr, PIKE) {} + QualType rebuild(ASTContext &Ctx, QualType T) const { T = Ctx.getQualifiedType(T, Quals); - PointerInterpretationKind DefaultPIK = - Ctx.getDefaultPointerInterpretation(); switch (K) { case Pointer: - return Ctx.getPointerType(T, PIK.getValueOr(DefaultPIK)); + assert(PIKE && "Pointer must have an interpretation"); + return Ctx.getPointerType(T, *PIKE); case MemberPointer: return Ctx.getMemberPointerType(T, ClassOrBound); case ObjCPointer: @@ -6775,10 +6779,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, (Ptr2 = Composite2->getAs())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); - if (Ptr1->getPointerInterpretation() != Ptr2->getPointerInterpretation()) + PointerInterpretationKindExplicit PIKE1 = + Ptr1->getPointerInterpretationExplicit(); + PointerInterpretationKindExplicit PIKE2 = + Ptr2->getPointerInterpretationExplicit(); + if (PIKE1.PIK != PIKE2.PIK) return QualType(); - Steps.emplace_back(Step::Pointer, nullptr, - Ptr1->getPointerInterpretation()); + PointerInterpretationKindExplicit PIKE = PIKE1.IsExplicit ? PIKE1 : PIKE2; + Steps.emplace_back(Step::Pointer, PIKE); continue; } @@ -6829,7 +6837,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, Composite2->isVoidPointerType()))) { Composite1 = Composite1->getPointeeType(); Composite2 = Composite2->getPointeeType(); - Steps.emplace_back(Step::Pointer); + Steps.emplace_back(Step::Pointer, + Context.getDefaultPointerInterpretationExplicit()); continue; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index dc57035dc05e..8cd12b1d4953 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2294,8 +2294,9 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr, if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType()) return ToType.getUnqualifiedType(); - const bool FromIsCap = FromPtr->isCHERICapabilityType(Context); - PointerInterpretationKind PIK = FromIsCap ? PIK_Capability : PIK_Integer; + llvm::Optional FromPIKE = + FromPtr->getPointerInterpretationExplicitOrNone(Context); + assert(FromPIKE && "Pointer must have an interpretation"); QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType()); QualType CanonToPointee = Context.getCanonicalType(ToPointee); @@ -2308,14 +2309,15 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr, if (CanonToPointee.getLocalQualifiers() == Quals) { // ToType is exactly what we need. Return it. // XXXAR: but only if the memory capability qualifier matches - if (ToType->isCHERICapabilityType(Context) == FromIsCap && !ToType.isNull()) + if (!ToType.isNull() && + ToType->getPointerInterpretationExplicitOrNone(Context) == *FromPIKE) return ToType.getUnqualifiedType(); // Build a pointer to ToPointee. It has the right qualifiers // already. if (isa(ToType)) return Context.getObjCObjectPointerType(ToPointee); - return Context.getPointerType(ToPointee, PIK); + return Context.getPointerType(ToPointee, *FromPIKE); } // Just build a canonical type that has the right qualifiers. @@ -2324,7 +2326,7 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr, if (isa(ToType)) return Context.getObjCObjectPointerType(QualifiedCanonToPointee); - return Context.getPointerType(QualifiedCanonToPointee, PIK); + return Context.getPointerType(QualifiedCanonToPointee, *FromPIKE); } static bool isNullPointerConstantForConversion(Expr *Expr, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 6de486be8f16..69dfd32ad389 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2292,6 +2292,11 @@ namespace { return Visit(T->getModifiedType()); } + TemplateTypeParmDecl * + VisitPointerInterpretationType(const PointerInterpretationType *T) { + return Visit(T->getModifiedType()); + } + TemplateTypeParmDecl *VisitMacroQualifiedType(const MacroQualifiedType *T) { return Visit(T->getUnderlyingType()); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 1809a8d037c2..4c958ffcfd01 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1,4 +1,4 @@ -//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===// + // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -2132,9 +2132,10 @@ static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType) { /// /// \returns A suitable pointer type, if there are no /// errors. Otherwise, returns a NULL type. -QualType Sema::BuildPointerType(QualType T, PointerInterpretationKind PIK, +QualType Sema::BuildPointerType(QualType T, + PointerInterpretationKindExplicit PIKE, SourceLocation Loc, DeclarationName Entity, - bool* ValidPointer) { + bool *ValidPointer) { if (T->isReferenceType()) { // C++ 8.3.2p4: There shall be no ... pointers to references ... Diag(Loc, diag::err_illegal_decl_pointer_to_reference) @@ -2163,8 +2164,9 @@ QualType Sema::BuildPointerType(QualType T, PointerInterpretationKind PIK, // If we are in purecap ABI turn pointers marked as using an integer // representation into a plain pointer-range-sized integer - if (PIK == PIK_Integer - && Context.getTargetInfo().areAllPointersCapabilities()) { + if (PIKE.PIK == PIK_Integer && + Context.getTargetInfo().areAllPointersCapabilities()) { + assert(PIKE.IsExplicit && "Cannot have implicit PIK_Integer with purecap"); // This is not a real pointer type in the purecap ABI // ptrdiff_t will be the same size as a plain mips pointer // FIXME: this ValidPointer approach is a HACK to ensure that we return @@ -2176,7 +2178,7 @@ QualType Sema::BuildPointerType(QualType T, PointerInterpretationKind PIK, // Build the pointer type. if (ValidPointer) *ValidPointer = true; - return Context.getPointerType(T, PIK); + return Context.getPointerType(T, PIKE); } /// Build a reference type. @@ -2389,10 +2391,11 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize, /// /// \returns A suitable array type, if there are no errors. Otherwise, /// returns a NULL type. -QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, - Expr *ArraySize, unsigned Quals, - SourceRange Brackets, DeclarationName Entity, - llvm::Optional PIK) { +QualType +Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, + Expr *ArraySize, unsigned Quals, SourceRange Brackets, + DeclarationName Entity, + llvm::Optional PIKE) { SourceLocation Loc = Brackets.getBegin(); if (getLangOpts().CPlusPlus) { @@ -2517,13 +2520,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (VLAIsError) return QualType(); - T = Context.getVariableArrayType(T, nullptr, ASM, Quals, Brackets, PIK); + T = Context.getVariableArrayType(T, nullptr, ASM, Quals, Brackets, PIKE); } else { - T = Context.getIncompleteArrayType(T, ASM, Quals, PIK); + T = Context.getIncompleteArrayType(T, ASM, Quals, PIKE); } } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets, - PIK); + PIKE); } else { ExprResult R = checkArraySize(*this, ArraySize, ConstVal, VLADiag, VLAIsError); @@ -2535,7 +2538,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, // that we can fold to a non-zero positive value as a non-VLA as an // extension. T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets, - PIK); + PIKE); } else if (!T->isDependentType() && !T->isIncompleteType() && !T->isConstantSizeType()) { // C99: an array with an element type that has a non-constant-size is a @@ -2545,7 +2548,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (VLAIsError) return QualType(); T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets, - PIK); + PIKE); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. @@ -2583,7 +2586,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } T = Context.getConstantArrayType(T, ConstVal, ArraySize, ASM, Quals, - PIK); + PIKE); } } @@ -4944,7 +4947,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } bool ValidPointer = false; - T = S.BuildPointerType(T, S.PointerInterpretation, DeclType.Loc, Name, + T = S.BuildPointerType(T, S.CurrentPIKE, DeclType.Loc, Name, &ValidPointer); if (!ValidPointer) { IsIntegerPointerInPureCapABI = true; // FIXME: is this correct? @@ -5043,14 +5046,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Array parameters have an interpretation based on the qualifiers // (deferred until attribute parsing) and default interpretation. All // other arrays are implicit based on their container (if any). - llvm::Optional PIK = llvm::None; + llvm::Optional PIKE = llvm::None; if (D.isPrototypeContext() && !hasOuterPointerLikeChunk(D, chunkIndex)) - PIK = Context.getDefaultPointerInterpretation(); + PIKE = Context.getDefaultPointerInterpretationExplicit(); T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, SourceRange(DeclType.Loc, DeclType.EndLoc), Name, - PIK); + PIKE); break; } case DeclaratorChunk::Function: { @@ -6375,6 +6378,19 @@ fillDependentPointerTypeLoc(DependentPointerTypeLoc DPTL, llvm_unreachable("no __capability qualifier found at the expected location!"); } +static void +fillPointerInterpretationTypeLoc(PointerInterpretationTypeLoc PITL, + const ParsedAttributesView &Attrs) { + for (const ParsedAttr &AL : Attrs) { + if (AL.getKind() == ParsedAttr::AT_CHERICapability) { + PITL.setQualifierRange(AL.getRange()); + return; + } + } + + llvm_unreachable("no __capability qualifier found at the expected location!"); +} + static void fillMatrixTypeLoc(MatrixTypeLoc MTL, const ParsedAttributesView &Attrs) { for (const ParsedAttr &AL : Attrs) { @@ -6432,6 +6448,12 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } + while (PointerInterpretationTypeLoc TL = + CurrTL.getAs()) { + fillPointerInterpretationTypeLoc(TL, D.getTypeObject(i).getAttrs()); + CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); + } + while (DependentAddressSpaceTypeLoc TL = CurrTL.getAs()) { fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); @@ -6979,6 +7001,7 @@ namespace { enum WrapKind { Desugar, Attributed, + PointerInterpretation, Parens, Array, Pointer, @@ -7020,6 +7043,9 @@ namespace { } else if (isa(Ty)) { T = cast(Ty)->getEquivalentType(); Stack.push_back(Attributed); + } else if (isa(Ty)) { + T = cast(Ty)->getEquivalentType(); + Stack.push_back(PointerInterpretation); } else if (isa(Ty)) { T = cast(Ty)->getUnderlyingType(); Stack.push_back(MacroQualified); @@ -7074,6 +7100,10 @@ namespace { case Attributed: return wrap(C, cast(Old)->getEquivalentType(), I); + case PointerInterpretation: + return wrap( + C, cast(Old)->getEquivalentType(), I); + case Parens: { QualType New = wrap(C, cast(Old)->getInnerType(), I); return C.getParenType(New); @@ -8162,19 +8192,23 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr, } } -QualType Sema::BuildPointerInterpretationAttr(QualType T, - PointerInterpretationKind PIK, - SourceLocation QualifierLoc) { +QualType Sema::BuildPointerInterpretationEquivalentType( + QualType T, PointerInterpretationKind PIK, SourceLocation QualifierLoc) { + // Equivalent type always has a canonical PIKE + PointerInterpretationKindExplicit PIKE = + Context.getCanonicalPointerInterpretationExplicit( + PointerInterpretationKindExplicit(PIK, /*IsExplicit=*/true)); + if (T->isPointerType() || T->isReferenceType()) { // preserve existing qualifiers on T Qualifiers Qs = T.getQualifiers(); if (const PointerType *PT = T->getAs()) - T = Context.getPointerType(PT->getPointeeType(), PIK); + T = Context.getPointerType(PT->getPointeeType(), PIKE); else if (const LValueReferenceType *LRT = T->getAs()) - T = Context.getLValueReferenceType(LRT->getPointeeType(), true, PIK); + T = Context.getLValueReferenceType(LRT->getPointeeType(), true, PIKE); else if (const RValueReferenceType *RRT = T->getAs()) - T = Context.getRValueReferenceType(RRT->getPointeeType(), PIK); + T = Context.getRValueReferenceType(RRT->getPointeeType(), PIKE); else llvm_unreachable("Don't know how to set the interpretation for T"); @@ -8192,18 +8226,17 @@ QualType Sema::BuildPointerInterpretationAttr(QualType T, if (const auto *VAT = dyn_cast(T)) T = Context.getVariableArrayType(EltTy, VAT->getSizeExpr(), ASM, - IndexTypeQuals, - VAT->getBracketsRange(), PIK); + IndexTypeQuals, VAT->getBracketsRange(), + PIKE); else if (const auto *DSAT = dyn_cast(T)) T = Context.getDependentSizedArrayType(EltTy, DSAT->getSizeExpr(), ASM, IndexTypeQuals, - DSAT->getBracketsRange(), PIK); + DSAT->getBracketsRange(), PIKE); else if (isa(T)) - T = Context.getIncompleteArrayType(EltTy, ASM, IndexTypeQuals, PIK); + T = Context.getIncompleteArrayType(EltTy, ASM, IndexTypeQuals, PIKE); else if (const auto *CAT = dyn_cast(T)) - T = Context.getConstantArrayType(EltTy, CAT->getSize(), - CAT->getSizeExpr(), ASM, - IndexTypeQuals, PIK); + T = Context.getConstantArrayType( + EltTy, CAT->getSize(), CAT->getSizeExpr(), ASM, IndexTypeQuals, PIKE); else llvm_unreachable("Don't know how to set the interpretation for T"); @@ -8330,8 +8363,10 @@ static void HandleCHERICapabilityQualifier(QualType &CurType, } assert(S.Context.getTargetInfo().SupportsCapabilities()); - CurType = S.BuildPointerInterpretationAttr(CurType, PIK_Capability, - attr.getLoc()); + QualType EquivType = S.BuildPointerInterpretationEquivalentType( + CurType, PIK_Capability, attr.getLoc()); + CurType = S.Context.getPointerInterpretationType( + PIK_Capability, attr.getRange(), CurType, EquivType); } static void handleCheriNoProvenanceAttr(QualType &T, TypeProcessingState &State, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 55587f845676..33d5047c78ed 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -750,7 +750,7 @@ class TreeTransform { /// By default, performs semantic analysis when building the pointer type. /// Subclasses may override this routine to provide different behavior. QualType RebuildPointerType(QualType PointeeType, - PointerInterpretationKind PIK, + PointerInterpretationKindExplicit PIKE, SourceLocation Sigil); /// Build a new block pointer type given its pointee type. @@ -813,61 +813,52 @@ class TreeTransform { /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. /// Also by default, all of the other Rebuild*Array - QualType RebuildArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt *Size, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK); + QualType + RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt *Size, Expr *SizeExpr, + unsigned IndexTypeQuals, SourceRange BracketsRange, + llvm::Optional PIKE); /// Build a new constant array type given the element type, size /// modifier, (known) size of the array, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildConstantArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK); + QualType RebuildConstantArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, Expr *SizeExpr, unsigned IndexTypeQuals, + SourceRange BracketsRange, + llvm::Optional PIKE); /// Build a new incomplete array type given the element type, size /// modifier, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildIncompleteArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK); + QualType RebuildIncompleteArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, + unsigned IndexTypeQuals, SourceRange BracketsRange, + llvm::Optional PIKE); /// Build a new variable-length array type given the element type, /// size modifier, size expression, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildVariableArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK); + QualType RebuildVariableArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, + Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange, + llvm::Optional PIKE); /// Build a new dependent-sized array type given the element type, /// size modifier, size expression, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildDependentSizedArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK); + QualType RebuildDependentSizedArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, + Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange, + llvm::Optional PIKE); /// Build a new vector type given the element type and /// number of elements. @@ -5040,7 +5031,7 @@ QualType TreeTransform::TransformPointerType(TypeLocBuilder &TLB, if (getDerived().AlwaysRebuild() || PointeeType != TL.getPointeeLoc().getType()) { Result = getDerived().RebuildPointerType( - PointeeType, T->getPointerInterpretation(), TL.getSigilLoc()); + PointeeType, T->getPointerInterpretationExplicit(), TL.getSigilLoc()); if (Result.isNull()) return QualType(); } @@ -5209,12 +5200,10 @@ TreeTransform::TransformConstantArrayType(TypeLocBuilder &TLB, if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || (T->getSizeExpr() && NewSize != OldSize)) { - Result = getDerived().RebuildConstantArrayType(ElementType, - T->getSizeModifier(), - T->getSize(), NewSize, - T->getIndexTypeCVRQualifiers(), - TL.getBracketsRange(), - T->getPointerInterpretation()); + Result = getDerived().RebuildConstantArrayType( + ElementType, T->getSizeModifier(), T->getSize(), NewSize, + T->getIndexTypeCVRQualifiers(), TL.getBracketsRange(), + T->getPointerInterpretationExplicit()); if (Result.isNull()) return QualType(); } @@ -5243,11 +5232,9 @@ QualType TreeTransform::TransformIncompleteArrayType( QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType()) { - Result = getDerived().RebuildIncompleteArrayType(ElementType, - T->getSizeModifier(), - T->getIndexTypeCVRQualifiers(), - TL.getBracketsRange(), - T->getPointerInterpretation()); + Result = getDerived().RebuildIncompleteArrayType( + ElementType, T->getSizeModifier(), T->getIndexTypeCVRQualifiers(), + TL.getBracketsRange(), T->getPointerInterpretationExplicit()); if (Result.isNull()) return QualType(); } @@ -5288,12 +5275,9 @@ TreeTransform::TransformVariableArrayType(TypeLocBuilder &TLB, if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || Size != T->getSizeExpr()) { - Result = getDerived().RebuildVariableArrayType(ElementType, - T->getSizeModifier(), - Size, - T->getIndexTypeCVRQualifiers(), - TL.getBracketsRange(), - T->getPointerInterpretation()); + Result = getDerived().RebuildVariableArrayType( + ElementType, T->getSizeModifier(), Size, T->getIndexTypeCVRQualifiers(), + TL.getBracketsRange(), T->getPointerInterpretationExplicit()); if (Result.isNull()) return QualType(); } @@ -5337,12 +5321,9 @@ TreeTransform::TransformDependentSizedArrayType(TypeLocBuilder &TLB, if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || size != origSize) { - Result = getDerived().RebuildDependentSizedArrayType(ElementType, - T->getSizeModifier(), - size, - T->getIndexTypeCVRQualifiers(), - TL.getBracketsRange(), - T->getPointerInterpretation()); + Result = getDerived().RebuildDependentSizedArrayType( + ElementType, T->getSizeModifier(), size, T->getIndexTypeCVRQualifiers(), + TL.getBracketsRange(), T->getPointerInterpretationExplicit()); if (Result.isNull()) return QualType(); } @@ -5597,6 +5578,37 @@ QualType TreeTransform::TransformDependentPointerType( return Result; } +template +QualType TreeTransform::TransformPointerInterpretationType( + TypeLocBuilder &TLB, PointerInterpretationTypeLoc TL) { + const PointerInterpretationType *T = TL.getTypePtr(); + + QualType ModifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc()); + if (ModifiedType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + + if (getDerived().AlwaysRebuild() || ModifiedType != T->getModifiedType()) { + // From TransformAttributedType: + // TODO: this is really lame; we should really be rebuilding the + // equivalent type from first principles. + QualType EquivalentType = + getDerived().TransformType(T->getEquivalentType()); + if (EquivalentType.isNull()) + return QualType(); + + Result = SemaRef.Context.getPointerInterpretationType( + T->getPointerInterpretation(), T->getQualifierRange(), ModifiedType, + EquivalentType); + } + + PointerInterpretationTypeLoc NewTL = + TLB.push(Result); + NewTL.setQualifierRange(TL.getQualifierRange()); + return Result; +} + template QualType TreeTransform::TransformVectorType(TypeLocBuilder &TLB, VectorTypeLoc TL) { @@ -14362,10 +14374,11 @@ TreeTransform::TransformAtomicExpr(AtomicExpr *E) { // Type reconstruction //===----------------------------------------------------------------------===// -template +template QualType TreeTransform::RebuildPointerType( - QualType PointeeType, PointerInterpretationKind PIK, SourceLocation Star) { - return SemaRef.BuildPointerType(PointeeType, PIK, Star, + QualType PointeeType, PointerInterpretationKindExplicit PIKE, + SourceLocation Star) { + return SemaRef.BuildPointerType(PointeeType, PIKE, Star, getDerived().getBaseEntity(), nullptr); } @@ -14432,19 +14445,16 @@ QualType TreeTransform::RebuildObjCObjectPointerType( return SemaRef.Context.getObjCObjectPointerType(PointeeType); } -template -QualType -TreeTransform::RebuildArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt *Size, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK) { +template +QualType TreeTransform::RebuildArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt *Size, Expr *SizeExpr, unsigned IndexTypeQuals, + SourceRange BracketsRange, + llvm::Optional PIKE) { if (SizeExpr || !Size) return SemaRef.BuildArrayType(ElementType, SizeMod, SizeExpr, IndexTypeQuals, BracketsRange, - getDerived().getBaseEntity(), PIK); + getDerived().getBaseEntity(), PIKE); QualType Types[] = { SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy, @@ -14464,59 +14474,46 @@ TreeTransform::RebuildArrayType(QualType ElementType, IntegerLiteral *ArraySize = IntegerLiteral::Create(SemaRef.Context, *Size, SizeType, /*FIXME*/BracketsRange.getBegin()); - return SemaRef.BuildArrayType(ElementType, SizeMod, ArraySize, - IndexTypeQuals, BracketsRange, - getDerived().getBaseEntity(), PIK); + return SemaRef.BuildArrayType(ElementType, SizeMod, ArraySize, IndexTypeQuals, + BracketsRange, getDerived().getBaseEntity(), + PIKE); } -template -QualType -TreeTransform::RebuildConstantArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - const llvm::APInt &Size, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK) { +template +QualType TreeTransform::RebuildConstantArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, Expr *SizeExpr, unsigned IndexTypeQuals, + SourceRange BracketsRange, + llvm::Optional PIKE) { return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr, - IndexTypeQuals, BracketsRange, PIK); + IndexTypeQuals, BracketsRange, PIKE); } -template -QualType -TreeTransform::RebuildIncompleteArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK) { +template +QualType TreeTransform::RebuildIncompleteArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, + unsigned IndexTypeQuals, SourceRange BracketsRange, + llvm::Optional PIKE) { return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, nullptr, - IndexTypeQuals, BracketsRange, PIK); + IndexTypeQuals, BracketsRange, PIKE); } -template -QualType -TreeTransform::RebuildVariableArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK) { - return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, - SizeExpr, - IndexTypeQuals, BracketsRange, PIK); +template +QualType TreeTransform::RebuildVariableArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, Expr *SizeExpr, + unsigned IndexTypeQuals, SourceRange BracketsRange, + llvm::Optional PIKE) { + return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, SizeExpr, + IndexTypeQuals, BracketsRange, PIKE); } -template -QualType -TreeTransform::RebuildDependentSizedArrayType(QualType ElementType, - ArrayType::ArraySizeModifier SizeMod, - Expr *SizeExpr, - unsigned IndexTypeQuals, - SourceRange BracketsRange, - llvm::Optional PIK) { - return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, - SizeExpr, - IndexTypeQuals, BracketsRange, PIK); +template +QualType TreeTransform::RebuildDependentSizedArrayType( + QualType ElementType, ArrayType::ArraySizeModifier SizeMod, Expr *SizeExpr, + unsigned IndexTypeQuals, SourceRange BracketsRange, + llvm::Optional PIKE) { + return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, SizeExpr, + IndexTypeQuals, BracketsRange, PIKE); } template @@ -14530,8 +14527,8 @@ template QualType TreeTransform::RebuildDependentPointerType( QualType PointerType, PointerInterpretationKind PIK, SourceLocation QualifierLoc) { - return SemaRef.BuildPointerInterpretationAttr(PointerType, PIK, - QualifierLoc); + return SemaRef.BuildPointerInterpretationEquivalentType(PointerType, PIK, + QualifierLoc); } template diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index e066ade8dc95..df6728d5ee0e 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6571,6 +6571,11 @@ void TypeLocReader::VisitDependentPointerTypeLoc( TL.setQualifierLoc(readSourceLocation()); } +void TypeLocReader::VisitPointerInterpretationTypeLoc( + PointerInterpretationTypeLoc TL) { + TL.setQualifierRange(Reader.readSourceRange()); +} + void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { TL.setNameLoc(readSourceLocation()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index d91477acecb0..06078880f49d 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -342,6 +342,13 @@ void TypeLocWriter::VisitDependentPointerTypeLoc( Record.AddSourceLocation(TL.getQualifierLoc()); } +void TypeLocWriter::VisitPointerInterpretationTypeLoc( + PointerInterpretationTypeLoc TL) { + SourceRange range = TL.getQualifierRange(); + Record.AddSourceLocation(range.getBegin()); + Record.AddSourceLocation(range.getEnd()); +} + void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); diff --git a/clang/test/CodeGen/cheri/cheri-ctofromint.c b/clang/test/CodeGen/cheri/cheri-ctofromint.c index c50e1da3e715..facd7a20c714 100644 --- a/clang/test/CodeGen/cheri/cheri-ctofromint.c +++ b/clang/test/CodeGen/cheri/cheri-ctofromint.c @@ -10,12 +10,12 @@ void* __capability foo(void *__capability x){ // hybrid-warning@-1{{the following conversion will result in a CToPtr operation}} // hybrid-note@-2{{if you really intended to use CToPtr use}} // hybrid-warning@-3{{cast to smaller integer type 'int' from 'void * __capability'}} - // purecap-warning@-4{{cast to smaller integer type 'int' from 'void *'}} + // purecap-warning@-4{{cast to smaller integer type 'int' from 'void * __capability' (aka 'void *')}} // CHECK-HYBRID: inttoptr // CHECK-PURECAP: [[CONV:%.+]] = sext i32 {{%.+}} to i64 // CHECK-PURECAP-NEXT: getelementptr i8, i8 addrspace(200)* null, i64 [[CONV]] return (void* __capability)pi; // purecap-warning@-1{{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} // hybrid-warning@-2{{cast to 'void * __capability' from smaller integer type 'int'}} - // purecap-warning@-3{{cast to 'void *' from smaller integer type 'int'}} + // purecap-warning@-3{{cast to 'void * __capability' (aka 'void *') from smaller integer type 'int'}} } diff --git a/clang/test/CodeGen/cheri/convert-cap-to-int.c b/clang/test/CodeGen/cheri/convert-cap-to-int.c index dcb2c7c4452c..c0d57fa18b42 100644 --- a/clang/test/CodeGen/cheri/convert-cap-to-int.c +++ b/clang/test/CodeGen/cheri/convert-cap-to-int.c @@ -24,7 +24,7 @@ long test_capptr_to_long(char *__capability cap) { return (long)cap; // expected-warning{{will result in a CToPtr operation}} // expected-note{{to get the virtual address use}} // AST-LABEL: FunctionDecl {{.+}} test_capptr_to_long // AST: CStyleCastExpr {{.+}} 'long' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } // CHECK-LABEL: define {{[^@]+}}@test_capptr_to_ptr_default @@ -42,7 +42,7 @@ char *test_capptr_to_ptr_default(char *__capability cap) { return (char *)cap; // expected-warning{{cast from capability type 'char * __capability' to non-capability type 'char *' is most likely an error}} // AST-LABEL: FunctionDecl {{.+}} test_capptr_to_ptr_default // AST: CStyleCastExpr {{.+}} 'char *' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } // CHECK-LABEL: define {{[^@]+}}@test_capptr_to_ptr_fromcap @@ -60,7 +60,7 @@ char *test_capptr_to_ptr_fromcap(char *__capability cap) { return (__cheri_fromcap char *)cap; // AST-LABEL: FunctionDecl {{.+}} test_capptr_to_ptr_fromcap // AST: CStyleCastExpr {{.+}} 'char *' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } // CHECK-LABEL: define {{[^@]+}}@test_capptr_to_ptr_addr @@ -82,7 +82,7 @@ char *test_capptr_to_ptr_addr(char *__capability cap) { // AST-LABEL: FunctionDecl {{.+}} test_capptr_to_ptr_addr // AST: CStyleCastExpr {{.+}} 'char *' // AST-NEXT: CStyleCastExpr {{.+}} 'long' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } /// intcap_t -> non-cap @@ -203,7 +203,7 @@ long test_capptr_to_long_via_intcap(char *__capability cap) { // AST-LABEL: FunctionDecl {{.+}} test_capptr_to_long_via_intcap // AST: CStyleCastExpr {{.+}} 'long' // AST-NEXT: CStyleCastExpr {{.+}} '__intcap' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } // CHECK-LABEL: define {{[^@]+}}@test_capptr_to_long_via_intcap_implicit @@ -223,7 +223,7 @@ long test_capptr_to_long_via_intcap_implicit(char *__capability cap) { // AST-LABEL: FunctionDecl {{.+}} test_capptr_to_long_via_intcap_implicit // AST: ImplicitCastExpr {{.+}} 'long' // AST-NEXT: CStyleCastExpr {{.+}} '__intcap' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } // CHECK-LABEL: define {{[^@]+}}@test_capptr_to_ptr_via_intcap_default @@ -244,7 +244,7 @@ char *test_capptr_to_ptr_via_intcap_default(char *__capability cap) { // AST-LABEL: FunctionDecl {{.+}} test_capptr_to_ptr_via_intcap_default // AST: CStyleCastExpr {{.+}} 'char *' // AST-NEXT: CStyleCastExpr {{.+}} '__intcap' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } // CHECK-LABEL: define {{[^@]+}}@test_capptr_to_ptr_via_intcap_fromcap @@ -263,7 +263,7 @@ char *test_capptr_to_ptr_via_intcap_fromcap(char *__capability cap) { // AST-LABEL: FunctionDecl {{.+}} test_capptr_to_ptr_via_intcap_fromcap // AST: CStyleCastExpr {{.+}} 'char *' // AST-NEXT: CStyleCastExpr {{.+}} '__intcap' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } // CHECK-LABEL: define {{[^@]+}}@test_capptr_to_ptr_via_intcap_addr @@ -286,7 +286,7 @@ char *test_capptr_to_ptr_via_intcap_addr(char *__capability cap) { // AST: CStyleCastExpr {{.+}} 'char *' // AST-NEXT: CStyleCastExpr {{.+}} 'long' // AST-NEXT: CStyleCastExpr {{.+}} '__intcap' - // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast } /// intcap_t -> non-cap with intermediate cast to void* __capability @@ -307,7 +307,7 @@ long test_intcap_to_long_via_capptr(__intcap cap) { return (long)(void *__capability)cap; // expected-warning{{will result in a CToPtr operation}} // expected-note{{to get the virtual address use}} // AST-LABEL: FunctionDecl {{.+}} test_intcap_to_long_via_capptr // AST: CStyleCastExpr {{.+}} 'long' - // AST-NEXT: CStyleCastExpr {{.+}} 'void * __capability' + // AST-NEXT: CStyleCastExpr {{.+}} 'void * __capability':'void * __capability' // AST-NEXT: ImplicitCastExpr {{.+}} '__intcap' part_of_explicit_cast } @@ -326,7 +326,7 @@ char *test_intcap_to_ptr_via_capptr(__intcap cap) { return (char *)(void *__capability)cap; // expected-warning{{cast from capability type 'void * __capability' to non-capability type 'char *' is most likely an error}} // AST-LABEL: FunctionDecl {{.+}} test_intcap_to_ptr_via_capptr // AST: CStyleCastExpr {{.+}} 'char *' - // AST-NEXT: CStyleCastExpr {{.+}} 'void * __capability' + // AST-NEXT: CStyleCastExpr {{.+}} 'void * __capability':'void * __capability' // AST-NEXT: ImplicitCastExpr {{.+}} '__intcap' part_of_explicit_cast } @@ -346,7 +346,7 @@ char *test_intcap_to_ptr_via_capptr_fromcap(__intcap cap) { // AST-LABEL: FunctionDecl {{.+}} test_intcap_to_ptr_via_capptr_fromcap // AST: ImplicitCastExpr {{.+}} 'char *' // AST-NEXT: CStyleCastExpr {{.+}} 'void *' - // AST-NEXT: CStyleCastExpr {{.+}} 'void * __capability' + // AST-NEXT: CStyleCastExpr {{.+}} 'void * __capability':'void * __capability' // AST-NEXT: ImplicitCastExpr {{.+}} '__intcap' part_of_explicit_cast } @@ -369,7 +369,7 @@ char *test_intcap_to_ptr_via_capptr_addr(__intcap cap) { // AST-LABEL: FunctionDecl {{.+}} test_intcap_to_ptr_via_capptr_addr // AST: CStyleCastExpr {{.+}} 'char *' // AST-NEXT: CStyleCastExpr {{.+}} 'long' - // AST-NEXT: CStyleCastExpr {{.+}} 'void * __capability' + // AST-NEXT: CStyleCastExpr {{.+}} 'void * __capability':'void * __capability' // AST-NEXT: ImplicitCastExpr {{.+}} '__intcap' part_of_explicit_cast } diff --git a/clang/test/CodeGen/cheri/convert-int-to-cap.c b/clang/test/CodeGen/cheri/convert-int-to-cap.c index e6b0f3462f67..ce3a93856a2c 100644 --- a/clang/test/CodeGen/cheri/convert-int-to-cap.c +++ b/clang/test/CodeGen/cheri/convert-int-to-cap.c @@ -47,7 +47,7 @@ char *__capability test_long_to_capptr(long l) { char *__capability test_intcap_to_capptr(__intcap l) { return (char *__capability)l; // AST-LABEL: FunctionDecl {{.+}} test_intcap_to_capptr - // AST: CStyleCastExpr {{.+}} 'char * __capability' + // AST: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: ImplicitCastExpr {{.+}} '__intcap' part_of_explicit_cast } @@ -62,7 +62,7 @@ char *__capability test_ptr_to_capptr_default(char *p) { // explicit-error@-1{{converting non-capability type 'char *' to capability type 'char * __capability' without an explicit cast}} // address-warning@-2{{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} // AST-LABEL: FunctionDecl {{.+}} test_ptr_to_capptr_default - // AST: CStyleCastExpr {{.+}} 'char * __capability' + // AST: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: ImplicitCastExpr {{.+}} 'char *' part_of_explicit_cast } @@ -94,7 +94,7 @@ char *__capability test_ptr_to_capptr_reinterpret_cast(char *p) { // explicit-error@-1{{converting non-capability type 'char *' to capability type 'char * __capability' without an explicit cast}} // address-warning@-2{{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} // CXX-AST-LABEL: FunctionDecl {{.+}} test_ptr_to_capptr_reinterpret_cast - // CXX-AST: CXXReinterpretCastExpr {{.+}} 'char * __capability' reinterpret_cast + // CXX-AST: CXXReinterpretCastExpr {{.+}} 'char * __capability':'char * __capability' reinterpret_cast // CXX-AST-NEXT: ImplicitCastExpr {{.+}} 'char *' part_of_explicit_cast } #endif @@ -108,7 +108,7 @@ char *__capability test_ptr_to_capptr_reinterpret_cast(char *p) { char *__capability test_ptr_to_capptr_tocap(char *p) { return (__cheri_tocap char *__capability)p; // AST-LABEL: FunctionDecl {{.+}} test_ptr_to_capptr_tocap - // AST: CStyleCastExpr {{.+}} 'char * __capability' + // AST: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: ImplicitCastExpr {{.+}} 'char *' part_of_explicit_cast } @@ -154,12 +154,12 @@ __intcap test_ptr_to_intcap_tocap(char *p) { char *__capability test_NULL(void) { return (char *__capability)NULL; // AST-LABEL: FunctionDecl {{.+}} test_NULL - // C-AST: CStyleCastExpr {{.+}} 'char * __capability' + // C-AST: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // C-AST-NEXT: ParenExpr {{.+}} 'void *' // C-AST-NEXT: CStyleCastExpr {{.+}} 'void *' // C-AST-NEXT: IntegerLiteral {{.+}} 'int' 0 - // CXX-AST: CStyleCastExpr {{.+}} 'char * __capability' - // CXX-AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // CXX-AST: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' + // CXX-AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast // CXX-AST-NEXT: GNUNullExpr {{.+}} 'long' } @@ -172,8 +172,8 @@ char *__capability test_zero_constant(void) { return (char *__capability)0; // AST-LABEL: FunctionDecl {{.+}} test_zero_constant // C-AST: CStyleCastExpr {{.+}} 'char * __capability __attribute__((cheri_no_provenance))':'char * __capability' - // CXX-AST: CStyleCastExpr {{.+}} 'char * __capability' - // CXX-AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // CXX-AST: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' + // CXX-AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast // AST-NEXT: IntegerLiteral {{.+}} 'int' 0 } @@ -186,8 +186,8 @@ char *__capability test_zero_constant(void) { char *__capability test_nullptr(void) { return (char *__capability)nullptr; // CXX-AST-LABEL: FunctionDecl {{.+}} test_nullptr - // CXX-AST: CStyleCastExpr {{.+}} 'char * __capability' - // CXX-AST: ImplicitCastExpr {{.+}} 'char * __capability' part_of_explicit_cast + // CXX-AST: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' + // CXX-AST: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' part_of_explicit_cast // CXX-AST-NEXT: CXXNullPtrLiteralExpr {{.+}} 'std::nullptr_t' } #endif diff --git a/clang/test/CodeGen/cheri/global-capinit.c b/clang/test/CodeGen/cheri/global-capinit.c index 8483b0bb4542..8c6dc3f45c5e 100644 --- a/clang/test/CodeGen/cheri/global-capinit.c +++ b/clang/test/CodeGen/cheri/global-capinit.c @@ -11,15 +11,15 @@ extern char extern_data; char *__capability global_cap_const = (char *__capability)(long)1234; // HYBRID: @global_cap_const = global i8 addrspace(200)* inttoptr (i64 1234 to i8 addrspace(200)*), align 16 // PURECAP: @global_cap_const = addrspace(200) global i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 1234), align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_const 'char * __capability' cinit +// AST-LABEL: VarDecl {{.+}} global_cap_const 'char * __capability':'char * __capability' cinit // AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability __attribute__((cheri_no_provenance))':'char * __capability' // AST-NEXT: CStyleCastExpr {{.+}} 'long' // AST-NEXT: IntegerLiteral {{.+}} 'int' 1234 char *__capability global_cap_const_tocap = (__cheri_tocap char *__capability)(char *)1234; // HYBRID-NEXT: @global_cap_const_tocap = global i8 addrspace(200)* inttoptr (i64 1234 to i8 addrspace(200)*), align 16 // PURECAP-NEXT: @global_cap_const_tocap = addrspace(200) global i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 1234), align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_const_tocap 'char * __capability' cinit -// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability' +// AST-LABEL: VarDecl {{.+}} global_cap_const_tocap 'char * __capability':'char * __capability' cinit +// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: CStyleCastExpr {{.+}} 'char *' // AST-NEXT: IntegerLiteral {{.+}} 'int' 1234 char *global_ptr_const = (char *)(long)1234; @@ -41,39 +41,39 @@ char *global_ptr_data = &extern_data; char *__capability global_cap_data_implicit = &extern_data; // implicit conversion to capability // HYBRID-NEXT: @global_cap_data_implicit = global i8 addrspace(200)* addrspacecast (i8* @extern_data to i8 addrspace(200)*), align 16 // PURECAP-NEXT: @global_cap_data_implicit = addrspace(200) global i8 addrspace(200)* @extern_data, align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_data_implicit 'char * __capability' cinit -// AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability' +// AST-LABEL: VarDecl {{.+}} global_cap_data_implicit 'char * __capability':'char * __capability' cinit +// AST-NEXT: ImplicitCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: UnaryOperator {{.+}} 'char *' prefix '&' cannot overflow // AST-NEXT: DeclRefExpr {{.+}} 'char' lvalue Var {{.+}} 'extern_data' 'char' char *__capability global_cap_data_default = (char *__capability) & extern_data; // HYBRID-NEXT: @global_cap_data_default = global i8 addrspace(200)* addrspacecast (i8* @extern_data to i8 addrspace(200)*), align 16 // PURECAP-NEXT: @global_cap_data_default = addrspace(200) global i8 addrspace(200)* @extern_data, align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_data_default 'char * __capability' cinit -// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability' +// AST-LABEL: VarDecl {{.+}} global_cap_data_default 'char * __capability':'char * __capability' cinit +// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: UnaryOperator {{.+}} 'char *' prefix '&' cannot overflow // AST-NEXT: DeclRefExpr {{.+}} 'char' lvalue Var {{.+}} 'extern_data' 'char' char *__capability global_cap_data_tocap = (__cheri_tocap char *__capability) & extern_data; // HYBRID-NEXT: @global_cap_data_tocap = global i8 addrspace(200)* addrspacecast (i8* @extern_data to i8 addrspace(200)*), align 16 // PURECAP-NEXT: @global_cap_data_tocap = addrspace(200) global i8 addrspace(200)* @extern_data, align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_data_tocap 'char * __capability' cinit -// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability' +// AST-LABEL: VarDecl {{.+}} global_cap_data_tocap 'char * __capability':'char * __capability' cinit +// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: UnaryOperator {{.+}} 'char *' prefix '&' cannot overflow // AST-NEXT: DeclRefExpr {{.+}} 'char' lvalue Var {{.+}} 'extern_data' 'char' /// The following two should result in an addrspacecast in hybrid mode: char *__capability global_cap_data_via_uintcap_explicit = (char *__capability)(unsigned __intcap)(char *__capability) & extern_data; // HYBRID-NEXT: @global_cap_data_via_uintcap_explicit = global i8 addrspace(200)* addrspacecast (i8* @extern_data to i8 addrspace(200)*), align 16 // PURECAP-NEXT: @global_cap_data_via_uintcap_explicit = addrspace(200) global i8 addrspace(200)* @extern_data, align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_data_via_uintcap_explicit 'char * __capability' cinit -// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability' +// AST-LABEL: VarDecl {{.+}} global_cap_data_via_uintcap_explicit 'char * __capability':'char * __capability' cinit +// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: CStyleCastExpr {{.+}} 'unsigned __intcap' -// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability' +// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: UnaryOperator {{.+}} 'char *' prefix '&' cannot overflow // AST-NEXT: DeclRefExpr {{.+}} 'char' lvalue Var {{.+}} 'extern_data' 'char' char *__capability global_cap_data_via_uintcap_default = (char *__capability)(unsigned __intcap)&extern_data; // HYBRID-NEXT: @global_cap_data_via_uintcap_default = global i8 addrspace(200)* addrspacecast (i8* @extern_data to i8 addrspace(200)*), align 16 // PURECAP-NEXT: @global_cap_data_via_uintcap_default = addrspace(200) global i8 addrspace(200)* @extern_data, align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_data_via_uintcap_default 'char * __capability' cinit -// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability' +// AST-LABEL: VarDecl {{.+}} global_cap_data_via_uintcap_default 'char * __capability':'char * __capability' cinit +// AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability':'char * __capability' // AST-NEXT: CStyleCastExpr {{.+}} 'unsigned __intcap' // AST-NEXT: UnaryOperator {{.+}} 'char *' prefix '&' cannot overflow // AST-NEXT: DeclRefExpr {{.+}} 'char' lvalue Var {{.+}} 'extern_data' 'char' @@ -81,7 +81,7 @@ char *__capability global_cap_data_addr_long = (char *__capability)(__cheri_addr // purecap-warning@-1{{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} // HYBRID-NEXT: @global_cap_data_addr_long = global i8 addrspace(200)* addrspacecast (i8* @extern_data to i8 addrspace(200)*), align 16 // PURECAP-NEXT: @global_cap_data_addr_long = addrspace(200) global i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 ptrtoint (i8 addrspace(200)* @extern_data to i64)), align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_data_addr_long 'char * __capability' cinit +// AST-LABEL: VarDecl {{.+}} global_cap_data_addr_long 'char * __capability':'char * __capability' cinit // AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability __attribute__((cheri_no_provenance))':'char * __capability' // AST-NEXT: CStyleCastExpr {{.+}} 'long' // AST-NEXT: UnaryOperator {{.+}} 'char *' prefix '&' cannot overflow @@ -90,7 +90,7 @@ char *__capability global_cap_data_via_long = (char *__capability)(long)&extern_ // purecap-warning@-1{{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} // HYBRID-NEXT: @global_cap_data_via_long = global i8 addrspace(200)* addrspacecast (i8* @extern_data to i8 addrspace(200)*), align 16 // PURECAP-NEXT: @global_cap_data_via_long = addrspace(200) global i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 ptrtoint (i8 addrspace(200)* @extern_data to i64)), align 16 -// AST-LABEL: VarDecl {{.+}} global_cap_data_via_long 'char * __capability' cinit +// AST-LABEL: VarDecl {{.+}} global_cap_data_via_long 'char * __capability':'char * __capability' cinit // AST-NEXT: CStyleCastExpr {{.+}} 'char * __capability __attribute__((cheri_no_provenance))':'char * __capability' // AST-NEXT: CStyleCastExpr {{.+}} 'long' // AST-NEXT: UnaryOperator {{.+}} 'char *' prefix '&' cannot overflow @@ -105,15 +105,15 @@ void (*global_fnptr)(void) = &extern_fn; void (*__capability global_fncap_default)(void) = (void (*__capability)(void)) & extern_fn; // HYBRID-NEXT: @global_fncap_default = global void () addrspace(200)* addrspacecast (void ()* @extern_fn to void () addrspace(200)*), align 16 // PURECAP-NEXT: @global_fncap_default = addrspace(200) global void () addrspace(200)* @extern_fn, align 16 -// AST-LABEL: VarDecl {{.+}} global_fncap_default 'void (* __capability)(void)' cinit -// AST-NEXT: CStyleCastExpr {{.+}} 'void (* __capability)(void)' +// AST-LABEL: VarDecl {{.+}} global_fncap_default 'void (* __capability)(void)':'void (* __capability)(void)' cinit +// AST-NEXT: CStyleCastExpr {{.+}} 'void (* __capability)(void)':'void (* __capability)(void)' // AST-NEXT: UnaryOperator {{.+}} 'void (*)(void)' prefix '&' cannot overflow // AST-NEXT: DeclRefExpr {{.+}} 'void (void)' Function {{.+}} 'extern_fn' 'void (void)' void (*__capability global_fncap_tocap)(void) = (__cheri_tocap void (*__capability)(void)) & extern_fn; // HYBRID-NEXT: @global_fncap_tocap = global void () addrspace(200)* addrspacecast (void ()* @extern_fn to void () addrspace(200)*), align 16 // PURECAP-NEXT: @global_fncap_tocap = addrspace(200) global void () addrspace(200)* @extern_fn, align 16 -// AST-LABEL: VarDecl {{.+}} global_fncap_tocap 'void (* __capability)(void)' cinit -// AST-NEXT: CStyleCastExpr {{.+}} 'void (* __capability)(void)' +// AST-LABEL: VarDecl {{.+}} global_fncap_tocap 'void (* __capability)(void)':'void (* __capability)(void)' cinit +// AST-NEXT: CStyleCastExpr {{.+}} 'void (* __capability)(void)':'void (* __capability)(void)' // AST-NEXT: UnaryOperator {{.+}} 'void (*)(void)' prefix '&' cannot overflow // AST-NEXT: DeclRefExpr {{.+}} 'void (void)' Function {{.+}} 'extern_fn' 'void (void)' diff --git a/clang/test/CodeGen/cheri/subobject-bounds-addrof-array.c b/clang/test/CodeGen/cheri/subobject-bounds-addrof-array.c index 464120d2349d..dc89b3137279 100644 --- a/clang/test/CodeGen/cheri/subobject-bounds-addrof-array.c +++ b/clang/test/CodeGen/cheri/subobject-bounds-addrof-array.c @@ -188,7 +188,7 @@ void test2(int *array) { // VERY-AGGRESSIVE: call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* %{{.+}}, i64 4) // CHECK: ret void - // DBG-NEXT: subscript 'int * __capability' subobj bounds check: array subscript on non-array type -> not setting bounds + // DBG-NEXT: subscript 'int *' subobj bounds check: array subscript on non-array type -> not setting bounds // DBG-SUBOBJECT-SAFE-NEXT: address 'int' subobj bounds check: Found array subscript -> index is a constant -> should set bounds on full array but size is not known -> not setting bounds // DBG-AGGRESSIVE-NEXT: address 'int' subobj bounds check: Found array subscript -> index is a constant -> should set bounds on full array but size is not known -> not setting bounds // DBG-VERY-AGGRESSIVE-NEXT: address 'int' subobj bounds check: Found array subscript -> index is a constant -> bounds-mode is very-aggressive -> bounds on array[CONST] are fine -> Found scalar type -> setting bounds for 'int' address to 4 diff --git a/clang/test/CodeGen/cheri/subobject-bounds-addrof-opt-out.c b/clang/test/CodeGen/cheri/subobject-bounds-addrof-opt-out.c index e6ab7f76e97d..326812b14eee 100644 --- a/clang/test/CodeGen/cheri/subobject-bounds-addrof-opt-out.c +++ b/clang/test/CodeGen/cheri/subobject-bounds-addrof-opt-out.c @@ -50,11 +50,11 @@ void test(struct WithBoundsPls* w, struct NoBoundsPls* n, struct HasMemberOfType do_stuff(n); // just passing on, no bounds do_stuff(&n[0]); // expected-remark-re{{not setting bounds for pointer to '{{(struct )?}}NoBoundsPls' (array type declaration has opt-out attribute)}} // expected-remark@-1{{not setting bounds for array subscript on 'struct NoBoundsPls *' (array subscript on non-array type)}} - // CHECK-NEXT: subscript 'struct NoBoundsPls * __capability' subobj bounds check: array subscript on non-array type -> not setting bounds + // CHECK-NEXT: subscript 'struct NoBoundsPls *' subobj bounds check: array subscript on non-array type -> not setting bounds // CHECK-NEXT: subobj bounds check: Found array subscript -> opt-out: array type declaration has opt-out attribute -> not setting bounds do_stuff(&n[2]); // expected-remark-re{{not setting bounds for pointer to '{{(struct )?}}NoBoundsPls' (array type declaration has opt-out attribute)}} // expected-remark@-1{{not setting bounds for array subscript on 'struct NoBoundsPls *' (array subscript on non-array type)}} - // CHECK-NEXT: subscript 'struct NoBoundsPls * __capability' subobj bounds check: array subscript on non-array type -> not setting bounds + // CHECK-NEXT: subscript 'struct NoBoundsPls *' subobj bounds check: array subscript on non-array type -> not setting bounds // CHECK-NEXT: subobj bounds check: Found array subscript -> opt-out: array type declaration has opt-out attribute -> not setting bounds do_stuff((struct WithBoundsPls*)n); // Setting bounds here do_stuff(&n2); // expected-remark-re{{not setting bounds for pointer to '{{(struct )?}}NoBoundsPls' (expression declaration has opt-out attribute)}} @@ -99,13 +99,13 @@ void test_stringbuf(int next_free) { do_stuff(&stringbuf[next_free]); // TODO: maybe don't do this by default for char[]? // expected-remark@-1{{setting sub-object bounds for pointer to 'char' to 1 bytes}} // expected-remark@-2{{not setting bounds for array subscript on 'char *' (array subscript on non-array type)}} - // CHECK-NEXT: subscript 'char * __capability' subobj bounds check: array subscript on non-array type -> not setting bounds + // CHECK-NEXT: subscript 'char *' subobj bounds check: array subscript on non-array type -> not setting bounds // CHECK-NEXT: subobj bounds check: Found array subscript -> Index is not a constant (probably in a per-element loop) -> Bounds mode is everywhere-unsafe -> setting bounds for 'char' address to 1 do_stuff(&stringbuf_opt_out[next_free]); // expected-remark@-1{{not setting bounds for pointer to 'char * __attribute__((cheri_no_subobject_bounds))' (array base type has opt-out attribute)}} // expected-remark@-2{{not setting bounds for array subscript on 'char * __attribute__((cheri_no_subobject_bounds))' (array subscript on non-array type)}} - // CHECK-NEXT: subscript 'char * __capability __attribute__((cheri_no_subobject_bounds))' subobj bounds check: array subscript on non-array type -> not setting bounds + // CHECK-NEXT: subscript 'char * __attribute__((cheri_no_subobject_bounds))' subobj bounds check: array subscript on non-array type -> not setting bounds // CHECK-NEXT: subobj bounds check: Found array subscript -> opt-out: array base type has opt-out attribute -> not setting bounds // Due to the parenthesized expression this was previous not parsed as an @@ -114,7 +114,7 @@ void test_stringbuf(int next_free) { // expected-remark@-1{{not setting bounds for pointer to 'char * __attribute__((cheri_no_subobject_bounds))' (array base type has opt-out attribute)}} // expected-remark@-2{{not setting bounds for array subscript on 'char * __attribute__((cheri_no_subobject_bounds))' (array subscript on non-array type)}} - // CHECK-NEXT: subscript 'char * __capability __attribute__((cheri_no_subobject_bounds))' subobj bounds check: array subscript on non-array type -> not setting bounds + // CHECK-NEXT: subscript 'char * __attribute__((cheri_no_subobject_bounds))' subobj bounds check: array subscript on non-array type -> not setting bounds // CHECK-NEXT: subobj bounds check: Found array subscript -> opt-out: array base type has opt-out attribute -> not setting bounds } @@ -271,11 +271,11 @@ struct fake_vla { void test_past_end_macro(struct fake_vla *fv) { do_stuff(fv->data[1]); // expected-remark-re{{setting sub-object bounds for field 'data' (array subscript on 'void *[1]') to {{16|32}} bytes}} - // CHECK-NEXT: subscript 'void * __capability[1]' subobj bounds check: got MemberExpr -> subscript on constant size array -> setting bounds for 'void * __capability[1]' subscript to {{16|32}} + // CHECK-NEXT: subscript 'void *[1]' subobj bounds check: got MemberExpr -> subscript on constant size array -> setting bounds for 'void *[1]' subscript to {{16|32}} do_stuff(__PAST_END(fv->data, 1)); // expected-remark{{not setting bounds for array subscript on 'typeof (*(fv->data)) *' (aka 'void **') (array subscript on non-array type)}} // expected-remark@-1 {{not setting bounds for array decay on 'void *[1]' (__builtin_no_change_bounds() expression)}} - // CHECK-NEXT: decay 'void * __capability[1]' subobj bounds check: __builtin_no_change_bounds() expression -> not setting bounds - // CHECK-NEXT: subscript 'typeof (*(fv->data)) * __capability' subobj bounds check: array subscript on non-array type -> not setting bounds + // CHECK-NEXT: decay 'void *[1]' subobj bounds check: __builtin_no_change_bounds() expression -> not setting bounds + // CHECK-NEXT: subscript 'typeof (*(fv->data)) *' subobj bounds check: array subscript on non-array type -> not setting bounds } #define cheri_unbounded_addressof(expr) (&__builtin_no_change_bounds(expr)) diff --git a/clang/test/CodeGen/cheri/subobject-bounds-addrof.c b/clang/test/CodeGen/cheri/subobject-bounds-addrof.c index 03c4f5d2764f..975006714928 100644 --- a/clang/test/CodeGen/cheri/subobject-bounds-addrof.c +++ b/clang/test/CodeGen/cheri/subobject-bounds-addrof.c @@ -80,11 +80,11 @@ struct WithAtomicInt { void test_atomic(atomic_int_t* array, struct WithAtomicInt *s) { do_stuff_with_void_ptr(&array[0]); // expected-remark {{not setting bounds for pointer to 'atomic_int_t' (aka '_Atomic(int)') (should set bounds on full array but size is not known)}} // expected-remark@-1{{not setting bounds for array subscript on 'atomic_int_t *' (aka '_Atomic(int) *') (array subscript on non-array type)}} - // DBG-NEXT: subscript 'atomic_int_t * __capability' subobj bounds check: array subscript on non-array type -> not setting bounds + // DBG-NEXT: subscript 'atomic_int_t *' subobj bounds check: array subscript on non-array type -> not setting bounds // DBG-NEXT: subobj bounds check: Found array subscript -> index is a constant -> should set bounds on full array but size is not known -> not setting bounds do_stuff_with_void_ptr(&array[2]); // expected-remark {{setting sub-object bounds for pointer to 'atomic_int_t' (aka '_Atomic(int)') to 4 bytes}} // expected-remark@-1{{not setting bounds for array subscript on 'atomic_int_t *' (aka '_Atomic(int) *') (array subscript on non-array type)}} - // DBG-NEXT: subscript 'atomic_int_t * __capability' subobj bounds check: array subscript on non-array type -> not setting bounds + // DBG-NEXT: subscript 'atomic_int_t *' subobj bounds check: array subscript on non-array type -> not setting bounds // DBG-NEXT: subobj bounds check: Found array subscript -> index is a constant -> const array index is not end and bounds==aggressive -> unwrapping _Atomic type -> Found scalar type -> setting bounds for 'atomic_int_t' address to 4 do_stuff_with_void_ptr(&at_int); // expected-remark {{setting bounds for pointer to 'atomic_int_t' (aka '_Atomic(int)') to 4 bytes}} // DBG-NEXT: subobj bounds check: unwrapping _Atomic type -> Found scalar type -> setting bounds for 'atomic_int_t' address to 4 diff --git a/clang/test/CodeGen/cheri/warn-ctoptr.c b/clang/test/CodeGen/cheri/warn-ctoptr.c index 46d8446102ab..4f8d842343ce 100644 --- a/clang/test/CodeGen/cheri/warn-ctoptr.c +++ b/clang/test/CodeGen/cheri/warn-ctoptr.c @@ -175,7 +175,7 @@ void *cast_uintcap_to_intptr_implicit(unsigned __intcap cap) { void *__capability cast_uintcap_to_cap_ptr_implicit(unsigned __intcap cap) { // Should also warn about ctoptr return cap; // expected-warning{{incompatible integer to pointer conversion returning 'unsigned __intcap' from a function with result type 'void * __capability'}} - // purecap-warning@-1{{incompatible integer to pointer conversion returning 'unsigned __intcap' from a function with result type 'void *'}} + // purecap-warning@-1{{incompatible integer to pointer conversion returning 'unsigned __intcap' from a function with result type 'void * __capability' (aka 'void *')}} } void *cast_uintcap_to_intptr_explicit(unsigned __intcap cap) { diff --git a/clang/test/CodeGenCXX/cheri/cheri-reference-member-size.cpp b/clang/test/CodeGenCXX/cheri/cheri-reference-member-size.cpp index be9fadf90f45..8a1d27654828 100644 --- a/clang/test/CodeGenCXX/cheri/cheri-reference-member-size.cpp +++ b/clang/test/CodeGenCXX/cheri/cheri-reference-member-size.cpp @@ -4,7 +4,7 @@ // CHECK-LABEL: *** Dumping AST Record Layout // CHECK-NEXT: 0 | class Foo -// CHECK-NEXT: 0 | class A & __capability _a +// CHECK-NEXT: 0 | class A & _a // CHECK-NEXT: | [sizeof=[[#CAP_SIZE]], // CHECK-SAME: dsize=[[#CAP_SIZE]], align=[[#CAP_SIZE]], // CHECK-NEXT: | nvsize=[[#CAP_SIZE]], nvalign=[[#CAP_SIZE]]] @@ -17,7 +17,7 @@ // CHECK-LABEL: *** Dumping AST Record Layout // CHECK-NEXT: 0 | class Bar // CHECK-NEXT: 0 | class Foo (base) -// CHECK-NEXT: 0 | class A & __capability _a +// CHECK-NEXT: 0 | class A & _a // CHECK-NEXT: [[#CAP_SIZE]] | int x // CHECK-NEXT: | [sizeof=[[#CAP_SIZE * 2]], dsize=[[#CAP_SIZE + 4]], align=[[#CAP_SIZE]], // CHECK-NEXT: | nvsize=[[#CAP_SIZE + 4]], nvalign=[[#CAP_SIZE]]] diff --git a/clang/test/CodeGenCXX/cheri/cheri-subclass-member.cpp b/clang/test/CodeGenCXX/cheri/cheri-subclass-member.cpp index dc27e46c6e9b..e8e23db1ea0b 100644 --- a/clang/test/CodeGenCXX/cheri/cheri-subclass-member.cpp +++ b/clang/test/CodeGenCXX/cheri/cheri-subclass-member.cpp @@ -8,8 +8,8 @@ // AST-NEXT: `-ReturnStmt // AST-NEXT: `-MemberExpr {{.+}} 'const long' lvalue ->size // AST-NEXT: `-ImplicitCastExpr {{.+}} 's1 * __capability' -// AST-NEXT: `-ImplicitCastExpr {{.+}} 'const s2 * __capability' -// AST-NEXT: `-DeclRefExpr {{.+}} 'const s2 * __capability' lvalue Var {{.+}} 'c_s2' 'const s2 * __capability' +// AST-NEXT: `-ImplicitCastExpr {{.+}} 'const s2 * __capability':'const s2 * __capability' +// AST-NEXT: `-DeclRefExpr {{.+}} 'const s2 * __capability':'const s2 * __capability' lvalue Var {{.+}} 'c_s2' 'const s2 * __capability':'const s2 * __capability' struct s1 { long size; diff --git a/clang/test/CodeGenCXX/cheri/dependent-cheri-casts.cpp b/clang/test/CodeGenCXX/cheri/dependent-cheri-casts.cpp index edbed5edac6f..15497fbda594 100644 --- a/clang/test/CodeGenCXX/cheri/dependent-cheri-casts.cpp +++ b/clang/test/CodeGenCXX/cheri/dependent-cheri-casts.cpp @@ -66,10 +66,10 @@ template int* cheri_fromcap_dep(srcty arg) { template int* __capability cheri_tocap_dep(srcty arg) { return (__cheri_tocap int* __capability)arg; // hybrid-error@-1{{invalid __cheri_tocap from 'long *' to unrelated type 'int * __capability'}} - // purecap-error@-2{{invalid __cheri_tocap from 'long *' to unrelated type 'int *'}} + // purecap-error@-2{{invalid __cheri_tocap from 'long *' to unrelated type 'int * __capability' (aka 'int *')}} // expected-error@-3{{invalid source type 'int' for __cheri_tocap: source must be a pointer}} // hybrid-warning@-4{{__cheri_tocap from 'int * __capability' to 'int * __capability' is a no-op}} - // purecap-warning@-5{{__cheri_tocap from 'int *' to 'int *' is a no-op}} + // purecap-warning@-5{{__cheri_tocap from 'int *' to 'int * __capability' (aka 'int *') is a no-op}} } // CHECK-LABEL: define {{[^@]+}}@_Z12fromcap_goodU12__capabilityPi diff --git a/clang/test/CodeGenCXX/cheri/reference-bounds-deref.cpp b/clang/test/CodeGenCXX/cheri/reference-bounds-deref.cpp index 67fe4d762fb3..7e9c185802b9 100644 --- a/clang/test/CodeGenCXX/cheri/reference-bounds-deref.cpp +++ b/clang/test/CodeGenCXX/cheri/reference-bounds-deref.cpp @@ -87,7 +87,7 @@ TEST_PTR_TO_REF(double) // Or void* TEST_PTR_TO_REF(void *) -// DEBUG-MSG-NEXT: Found scalar type -> setting bounds for 'void * __capability' reference to [[#CAP_SIZE]] +// DEBUG-MSG-NEXT: Found scalar type -> setting bounds for 'void *' reference to [[#CAP_SIZE]] // CHECK-LABEL: define dso_local void @_Z10test_derefPPv(i8 addrspace(200)* addrspace(200)* // CHECK: call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* %{{.+}}, // CHECK-SAME: i64 [[#CAP_SIZE]]) diff --git a/clang/test/Sema/cheri/cheri-cap-offset-addr-casts.c b/clang/test/Sema/cheri/cheri-cap-offset-addr-casts.c index 42dbf9a89c2f..87ac3449e5be 100644 --- a/clang/test/Sema/cheri/cheri-cap-offset-addr-casts.c +++ b/clang/test/Sema/cheri/cheri-cap-offset-addr-casts.c @@ -7,22 +7,21 @@ // void checkAST(char * __capability c) { - // HYBRID-AST: |-FunctionDecl {{.+}} line:9:6 checkAST 'void (char * __capability)' - // PURECAP-AST: |-FunctionDecl {{.+}} line:9:6 checkAST 'void (char *)' + // AST: |-FunctionDecl {{.+}} line:9:6 checkAST 'void (char * __capability)' long x1 = (__cheri_offset long)c; // AST: CStyleCastExpr {{.*}} {{.*}} 'long' {{$}} // The part_of_explicit_cast was not being set previously - // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability' part_of_explicit_cast{{$}} - // HYBRID-AST-NEXT: -DeclRefExpr {{.+}} 'char * __capability' lvalue ParmVar {{.+}} 'c' 'char * __capability'{{$}} - // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char *' part_of_explicit_cast{{$}} - // PURECAP-AST-NEXT: -DeclRefExpr {{.+}} 'char *' lvalue ParmVar {{.+}} 'c' 'char *'{{$}} + // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability':'char * __capability' part_of_explicit_cast{{$}} + // HYBRID-AST-NEXT: -DeclRefExpr {{.+}} 'char * __capability':'char * __capability' lvalue ParmVar {{.+}} 'c' 'char * __capability':'char * __capability'{{$}} + // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability':'char *' part_of_explicit_cast{{$}} + // PURECAP-AST-NEXT: -DeclRefExpr {{.+}} 'char * __capability':'char *' lvalue ParmVar {{.+}} 'c' 'char * __capability':'char *'{{$}} long x2 = (__cheri_addr long)c; // AST: CStyleCastExpr {{.*}} {{.*}} 'long' {{$}} - // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability' part_of_explicit_cast{{$}} - // HYBRID-AST-NEXT: -DeclRefExpr {{.+}} 'char * __capability' lvalue ParmVar {{.+}} 'c' 'char * __capability'{{$}} - // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char *' part_of_explicit_cast{{$}} - // PURECAP-AST-NEXT: -DeclRefExpr {{.+}} 'char *' lvalue ParmVar {{.+}} 'c' 'char *'{{$}} + // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability':'char * __capability' part_of_explicit_cast{{$}} + // HYBRID-AST-NEXT: -DeclRefExpr {{.+}} 'char * __capability':'char * __capability' lvalue ParmVar {{.+}} 'c' 'char * __capability':'char * __capability'{{$}} + // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability':'char *' part_of_explicit_cast{{$}} + // PURECAP-AST-NEXT: -DeclRefExpr {{.+}} 'char * __capability':'char *' lvalue ParmVar {{.+}} 'c' 'char * __capability':'char *'{{$}} } void types_offset(char * __capability c) { @@ -31,7 +30,7 @@ void types_offset(char * __capability c) { long x3 = (__cheri_offset long)c; char * __capability x4 = (__cheri_offset char * __capability)c; // hybrid-error@-1 {{invalid target type 'char * __capability' for __cheri_offset}} - // purecap-error@-2 {{invalid target type 'char *' for __cheri_offset}} + // purecap-error@-2 {{invalid target type 'char * __capability' (aka 'char *') for __cheri_offset}} long x5 = (__cheri_offset short)c; // expected-warning {{target type 'short' is smaller than the type 'long int' of the capability offset field}} short x6 = (__cheri_offset long)c; char *x7 = (__cheri_offset char*)c; // expected-error {{invalid target type 'char *' for __cheri_offset}} @@ -44,7 +43,7 @@ void types_addr(char * __capability c) { long x3 = (__cheri_addr long)c; char * __capability x4 = (__cheri_addr char * __capability)c; // hybrid-error@-1 {{capability type 'char * __capability' is not a valid target type for __cheri_addr}} - // purecap-error@-2 {{capability type 'char *' is not a valid target type for __cheri_addr}} + // purecap-error@-2 {{capability type 'char * __capability' (aka 'char *') is not a valid target type for __cheri_addr}} long x5 = (__cheri_addr short)c; // expected-warning {{target type 'short' is smaller than the type 'long int' of the address}} short x6 = (__cheri_addr long)c; char *x7 = (__cheri_addr char *)c; diff --git a/clang/test/Sema/cheri/cheri-cap-ptr-casts.c b/clang/test/Sema/cheri/cheri-cap-ptr-casts.c index 4c320d635074..7c460c738ed1 100644 --- a/clang/test/Sema/cheri/cheri-cap-ptr-casts.c +++ b/clang/test/Sema/cheri/cheri-cap-ptr-casts.c @@ -18,7 +18,7 @@ void a() { // hybrid-c-error-re@-1 {{cast from 'unsigned long *' to 'int * __capability *' increases required alignment from 8 to {{16|32}}}} // hybrid-c-note@-2 {{use __builtin_assume_aligned(..., sizeof(void* __capability)) if you know that the source type is sufficiently aligned}} // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'int * __capability *' {{$}} - // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'int **' {{$}} + // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'int * __capability *' {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} {{.*}} 'unsigned long *' part_of_explicit_cast{{$}} } @@ -29,55 +29,54 @@ void f() { char * __capability bufp; void (* __capability fp)(); bufp = (__cheri_tocap char * __capability) buf; - // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability' {{$}} - // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'char *' {{$}} + // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability':'char * __capability' {{$}} + // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability':'char *' {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} {{.*}} 'char *' part_of_explicit_cast{{$}} fp = (__cheri_tocap void (* __capability)()) f; - // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void (* __capability)()' {{$}} - // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void (*)()' {{$}} + // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void (* __capability)()':'void (* __capability)()' {{$}} + // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void (* __capability)()':'void (*)()' {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} {{.*}} 'void (*)()' part_of_explicit_cast{{$}} } void fromcap(void *__capability voidcap) { // AST-LABEL: FunctionDecl - // HYBRID-AST-SAME: fromcap 'void (void * __capability)' - // PURECAP-AST-SAME: fromcap 'void (void *)' + // AST-SAME: fromcap 'void (void * __capability)' char * __capability x; // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'char *' {{$}} - // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability' part_of_explicit_cast{{$}} - // HYBRID-AST-NEXT: DeclRefExpr {{.*}} 'char * __capability' lvalue Var {{.+}} 'x' 'char * __capability'{{$}} + // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability':'char * __capability' part_of_explicit_cast{{$}} + // HYBRID-AST-NEXT: DeclRefExpr {{.*}} 'char * __capability':'char * __capability' lvalue Var {{.+}} 'x' 'char * __capability':'char * __capability'{{$}} // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'char *' {{$}} - // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char *' part_of_explicit_cast{{$}} - // PURECAP-AST-NEXT: DeclRefExpr {{.*}} 'char *' lvalue Var {{.+}} 'x' 'char *'{{$}} + // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability':'char *' part_of_explicit_cast{{$}} + // PURECAP-AST-NEXT: DeclRefExpr {{.*}} 'char * __capability':'char *' lvalue Var {{.+}} 'x' 'char * __capability':'char *'{{$}} char *y = (__cheri_fromcap char *)x; // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void *' {{$}} // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'void * __capability' part_of_explicit_cast{{$}} - // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability' part_of_explicit_cast{{$}} - // HYBRID-AST-NEXT: DeclRefExpr {{.*}} 'char * __capability' lvalue Var {{.+}} 'x' 'char * __capability'{{$}} + // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability':'char * __capability' part_of_explicit_cast{{$}} + // HYBRID-AST-NEXT: DeclRefExpr {{.*}} 'char * __capability':'char * __capability' lvalue Var {{.+}} 'x' 'char * __capability':'char * __capability'{{$}} // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void *' {{$}} // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'void *' part_of_explicit_cast{{$}} - // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char *' part_of_explicit_cast{{$}} - // PURECAP-AST-NEXT: DeclRefExpr {{.*}} 'char *' lvalue Var {{.+}} 'x' 'char *'{{$}} + // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability':'char *' part_of_explicit_cast{{$}} + // PURECAP-AST-NEXT: DeclRefExpr {{.*}} 'char * __capability':'char *' lvalue Var {{.+}} 'x' 'char * __capability':'char *'{{$}} void *z = (__cheri_fromcap void *)x; // Check that we insert the appropriate bitcasts in the purecap ABI void *p1 = (__cheri_fromcap void *)voidcap; // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void *' {{$}} - // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'void * __capability' part_of_explicit_cast{{$}} - // HYBRID-AST-NEXT: DeclRefExpr {{.*}} 'void * __capability' lvalue ParmVar {{.+}} 'voidcap' 'void * __capability'{{$}} + // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'void * __capability':'void * __capability' part_of_explicit_cast{{$}} + // HYBRID-AST-NEXT: DeclRefExpr {{.*}} 'void * __capability':'void * __capability' lvalue ParmVar {{.+}} 'voidcap' 'void * __capability':'void * __capability'{{$}} // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void *' {{$}} - // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'void *' part_of_explicit_cast{{$}} - // PURECAP-AST-NEXT: DeclRefExpr {{.*}} 'void *' lvalue ParmVar {{.+}} 'voidcap' 'void *'{{$}} + // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'void * __capability':'void *' part_of_explicit_cast{{$}} + // PURECAP-AST-NEXT: DeclRefExpr {{.*}} 'void * __capability':'void *' lvalue ParmVar {{.+}} 'voidcap' 'void * __capability':'void *'{{$}} char *p2 = (__cheri_fromcap char *)voidcap; // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'char *' {{$}} // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'char * __capability' part_of_explicit_cast{{$}} - // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'void * __capability' part_of_explicit_cast{{$}} - // HYBRID-AST-NEXT: DeclRefExpr {{.*}} 'void * __capability' lvalue ParmVar {{.+}} 'voidcap' 'void * __capability'{{$}} + // HYBRID-AST-NEXT: ImplicitCastExpr {{.*}} 'void * __capability':'void * __capability' part_of_explicit_cast{{$}} + // HYBRID-AST-NEXT: DeclRefExpr {{.*}} 'void * __capability':'void * __capability' lvalue ParmVar {{.+}} 'voidcap' 'void * __capability':'void * __capability'{{$}} // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'char *' {{$}} // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'char *' part_of_explicit_cast{{$}} - // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'void *' part_of_explicit_cast{{$}} - // PURECAP-AST-NEXT: DeclRefExpr {{.*}} 'void *' lvalue ParmVar {{.+}} 'voidcap' 'void *'{{$}} + // PURECAP-AST-NEXT: ImplicitCastExpr {{.*}} 'void * __capability':'void *' part_of_explicit_cast{{$}} + // PURECAP-AST-NEXT: DeclRefExpr {{.*}} 'void * __capability':'void *' lvalue ParmVar {{.+}} 'voidcap' 'void * __capability':'void *'{{$}} } void tocap(void * voidptr) { @@ -86,25 +85,25 @@ void tocap(void * voidptr) { char *x; char * __capability y = (__cheri_tocap char * __capability)x; - // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability' {{$}} - // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'char *' {{$}} + // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability':'char * __capability' {{$}} + // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability':'char *' {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} 'char *' part_of_explicit_cast{{$}} // AST-NEXT: DeclRefExpr {{.*}} 'char *' lvalue Var {{.+}} 'x' 'char *'{{$}} void * __capability z = (__cheri_tocap void * __capability)x; - // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability' {{$}} - // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void *' {{$}} + // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability':'void * __capability' {{$}} + // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability':'void *' {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} 'void *' part_of_explicit_cast{{$}} // AST-NEXT: ImplicitCastExpr {{.*}} 'char *' part_of_explicit_cast{{$}} // AST-NEXT: DeclRefExpr {{.*}} 'char *' lvalue Var {{.+}} 'x' 'char *'{{$}} void * __capability p1 = (__cheri_tocap void * __capability)voidptr; - // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability' {{$}} - // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void *' {{$}} + // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability':'void * __capability' {{$}} + // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability':'void *' {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} 'void *' part_of_explicit_cast{{$}} // AST-NEXT: DeclRefExpr {{.*}} 'void *' lvalue ParmVar {{.+}} 'voidptr' 'void *'{{$}} char * __capability p2 = (__cheri_tocap char * __capability)voidptr; - // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability' {{$}} - // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'char *' {{$}} + // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability':'char * __capability' {{$}} + // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'char * __capability':'char *' {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} 'char *' part_of_explicit_cast{{$}} // AST-NEXT: ImplicitCastExpr {{.*}} 'void *' part_of_explicit_cast{{$}} // AST-NEXT: DeclRefExpr {{.*}} 'void *' lvalue ParmVar {{.+}} 'voidptr' 'void *'{{$}} @@ -121,8 +120,8 @@ struct a noop_void_cast(struct a *arg) { struct a first; first.ptr = (__cheri_tocap void *__capability)arg; // The following used to generate a NoOp cast that changed types in the purecap ABI (and then caused codegen to crash): - // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability' {{$}} - // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void *' {{$}} + // HYBRID-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability':'void * __capability' {{$}} + // PURECAP-AST: CStyleCastExpr {{.*}} {{.*}} 'void * __capability':'void *' {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} 'void *' part_of_explicit_cast{{$}} // AST-NEXT: ImplicitCastExpr {{.*}} 'struct a *' part_of_explicit_cast{{$}} // AST-NEXT: DeclRefExpr {{.*}} 'struct a *' lvalue ParmVar {{.+}} 'arg' 'struct a *'{{$}} diff --git a/clang/test/Sema/cheri/cheri-cap-to-int-cast.c b/clang/test/Sema/cheri/cheri-cap-to-int-cast.c index 00b3488ab27d..0277e6a6d349 100644 --- a/clang/test/Sema/cheri/cheri-cap-to-int-cast.c +++ b/clang/test/Sema/cheri/cheri-cap-to-int-cast.c @@ -79,24 +79,24 @@ struct test { void foo(void) { unsigned long x1 = (unsigned long)a; // hybrid-warning@-1{{cast from capability type 'void * __capability' to non-capability, non-address type 'unsigned long' is most likely an error}} - // purecap-warning@-2{{cast from capability type 'void *' to non-capability, non-address type 'unsigned long' is most likely an error}} + // purecap-warning@-2{{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'unsigned long' is most likely an error}} // AST: CStyleCastExpr {{.+}} 'unsigned long' long x2 = (long)a; // hybrid-warning@-1{{cast from capability type 'void * __capability' to non-capability, non-address type 'long' is most likely an error}} - // purecap-warning@-2{{cast from capability type 'void *' to non-capability, non-address type 'long' is most likely an error}} + // purecap-warning@-2{{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'long' is most likely an error}} // AST: CStyleCastExpr {{.+}} 'long' int x3 = (int)a; // hybrid-warning@-1{{cast from capability type 'void * __capability' to non-capability, non-address type 'int' is most likely an error}} - // purecap-warning@-2{{cast from capability type 'void *' to non-capability, non-address type 'int' is most likely an error}} + // purecap-warning@-2{{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'int' is most likely an error}} // hybrid-warning@-3{{cast to smaller integer type 'int' from 'void * __capability'}} - // purecap-warning@-4{{cast to smaller integer type 'int' from 'void *'}} + // purecap-warning@-4{{cast to smaller integer type 'int' from 'void * __capability' (aka 'void *')}} // AST: CStyleCastExpr {{.+}} 'int' ptrdiff_t x4 = (ptrdiff_t)a; // hybrid-warning@-1{{cast from capability type 'void * __capability' to non-capability, non-address type 'ptrdiff_t' (aka 'long') is most likely an error}} - // purecap-warning@-2{{cast from capability type 'void *' to non-capability, non-address type 'ptrdiff_t' (aka 'long') is most likely an error}} + // purecap-warning@-2{{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'ptrdiff_t' (aka 'long') is most likely an error}} // AST: CStyleCastExpr {{.+}} 'ptrdiff_t':'long' // These are okay @@ -114,7 +114,7 @@ void foo(void) { other_addr_t x11 = (other_addr_t)a; // AST: CStyleCastExpr {{.+}} 'ptraddr_t':'unsigned long' void* __capability x12 = (void* __capability)a; - // AST: CStyleCastExpr {{.+}} 'void * __capability' + // AST: CStyleCastExpr {{.+}} 'void * __capability':'void * __capability' int x13 = (int)(uintptr_t)a; // TODO: later on this should probably also be an error // AST: CStyleCastExpr {{.+}} 'int' // AST-NEXT: CStyleCastExpr {{.+}} 'uintptr_t':'unsigned __intcap' @@ -122,7 +122,7 @@ void foo(void) { // AST: CStyleCastExpr {{.+}} 'int' // AST-NEXT: CStyleCastExpr {{.+}} 'ptraddr_t':'unsigned long' word* __capability x15 = (word* __capability)a; - // AST: CStyleCastExpr {{.+}} 'word * __capability' + // AST: CStyleCastExpr {{.+}} 'word * __capability':'word * __capability' long x16 = (long __attribute__((memory_address)))a; // no warning // AST: CStyleCastExpr {{.+}} 'long __attribute__((memory_address))':'long' @@ -141,7 +141,7 @@ void test_cheri_to_from_cap(void) { int * x = 0; (__cheri_tocap char* __capability)x; // hybrid-error@-1{{invalid __cheri_tocap from 'int *' to unrelated type 'char * __capability'}} - // purecap-error@-2{{invalid __cheri_tocap from 'int *' to unrelated type 'char *'}} + // purecap-error@-2{{invalid __cheri_tocap from 'int *' to unrelated type 'char * __capability' (aka 'char *')}} (__cheri_tocap struct test* __capability)t; // expected-error{{invalid source type 'struct test' for __cheri_tocap: source must be a pointer}} (__cheri_tocap struct test)tptr; // expected-error{{invalid target type 'struct test' for __cheri_tocap: target must be a capability}} (__cheri_fromcap struct test*)t; // expected-error{{invalid source type 'struct test' for __cheri_fromcap: source must be a capability}} @@ -152,21 +152,21 @@ void test_cheri_to_from_cap(void) { // expected-warning@-1 {{__cheri_fromcap from 'struct test *' to 'struct test *' is a no-op}} #endif int* __capability intptr_to_cap = (__cheri_tocap int* __capability)x; - // purecap-warning@-1 {{__cheri_tocap from 'int *' to 'int *' is a no-op}} + // purecap-warning@-1 {{__cheri_tocap from 'int *' to 'int * __capability' (aka 'int *') is a no-op}} #ifndef __CHERI_PURE_CAPABILITY__ // Check no-op warning when in hybrid ABI int* __capability intptr_to_cap2 = (__cheri_tocap int* __capability)intptr_to_cap; // expected-warning@-1 {{__cheri_tocap from 'int * __capability' to 'int * __capability' is a no-op}} #endif - // AST: CStyleCastExpr {{.+}} 'int * __capability' + // AST: CStyleCastExpr {{.+}} 'int * __capability':'int * __capability' const int* __capability const_intcap = (__cheri_tocap int* __capability)x; - // purecap-warning@-1 {{__cheri_tocap from 'int *' to 'int *' is a no-op}} - // AST: ImplicitCastExpr {{.+}} 'const int * __capability' - // AST-NEXT: CStyleCastExpr {{.+}} 'int * __capability' + // purecap-warning@-1 {{__cheri_tocap from 'int *' to 'int * __capability' (aka 'int *') is a no-op}} + // AST: ImplicitCastExpr {{.+}} 'const int * __capability':'const int * __capability' + // AST-NEXT: CStyleCastExpr {{.+}} 'int * __capability':'int * __capability' (__cheri_tocap int* __capability)const_intcap; // hybrid-error@-1{{invalid __cheri_tocap from 'const int * __capability' to unrelated type 'int * __capability'}} - // purecap-error@-2{{invalid __cheri_tocap from 'const int *' to unrelated type 'int *'}} + // purecap-error@-2{{invalid __cheri_tocap from 'const int * __capability' (aka 'const int *') to unrelated type 'int * __capability' (aka 'int *')}} (__cheri_fromcap int* __capability)const_intcap; // hybrid-error@-1{{invalid __cheri_fromcap from 'const int * __capability' to unrelated type 'int * __capability'}} - // purecap-error@-2{{invalid __cheri_fromcap from 'const int *' to unrelated type 'int *'}} + // purecap-error@-2{{invalid __cheri_fromcap from 'const int * __capability' (aka 'const int *') to unrelated type 'int * __capability' (aka 'int *')}} } diff --git a/clang/test/Sema/cheri/cheri-capability-qualifier-declspec.c b/clang/test/Sema/cheri/cheri-capability-qualifier-declspec.c index 2c86c6c4bd60..97f08012a254 100644 --- a/clang/test/Sema/cheri/cheri-capability-qualifier-declspec.c +++ b/clang/test/Sema/cheri/cheri-capability-qualifier-declspec.c @@ -16,10 +16,6 @@ static __capability typeof(global_intptr) global_intcap = 0; _Static_assert(__builtin_types_compatible_p(typeof(global_intptr), int *), ""); _Static_assert(__builtin_types_compatible_p(typeof(global_intcap), int *__capability), ""); -/// Crash reproducer for https://github.com/CTSRD-CHERI/llvm-project/issues/710 -// RUN: not --crash %cheri_cc1 %s -fsyntax-only -verify -DCRASH -// REQUIRES: asserts -#ifdef CRASH struct s { int i; }; @@ -27,4 +23,3 @@ static struct s *global_sptr = 0; static __capability typeof(global_sptr) global_scap = 0; _Static_assert(__builtin_types_compatible_p(typeof(global_sptr), struct s *), ""); _Static_assert(__builtin_types_compatible_p(typeof(global_scap), struct s *__capability), ""); -#endif diff --git a/clang/test/Sema/cheri/cheri-int-to-cap-cast.c b/clang/test/Sema/cheri/cheri-int-to-cap-cast.c index 8f767b781154..53d5c99f1874 100644 --- a/clang/test/Sema/cheri/cheri-int-to-cap-cast.c +++ b/clang/test/Sema/cheri/cheri-int-to-cap-cast.c @@ -1,18 +1,21 @@ // RUN: %cheri_cc1 -o - %s -fsyntax-only -verify=expected,hybrid -// RUN: %cheri_purecap_cc1 -o - %s -fsyntax-only -verify=expected,purecap +// RUN: %cheri_purecap_cc1 -o - %s -fsyntax-only -verify=expected,purecap,purecap-c // RUN: %cheri_cc1 -o - -x c++ %s -fsyntax-only -verify=expected,hybrid -// RUN: %cheri_purecap_cc1 -o - -x c++ %s -fsyntax-only -verify=expected,purecap +// RUN: %cheri_purecap_cc1 -o - -x c++ %s -fsyntax-only -verify=expected,purecap,purecap-cxx void test_explicit_cast(int x, long y) { void *ptr; void * __capability cap; - // Explicit C-style casts should behave identically between C and C++. + // Explicit C-style casts should behave identically between C and C++, but + // upstream seems to differ on whether the original or canonical type is + // used for the diagnostics. cap = (void * __capability)x; // hybrid-warning@-1 {{cast to 'void * __capability' from smaller integer type 'int'}} - // purecap-warning@-2 {{cast to 'void *' from smaller integer type 'int'}} - // purecap-warning@-3 {{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} + // purecap-c-warning@-2 {{cast to 'void * __capability' (aka 'void *') from smaller integer type 'int'}} + // purecap-cxx-warning@-3 {{cast to 'void *' from smaller integer type 'int'}} + // purecap-warning@-4 {{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} ptr = (void *)x; // expected-warning@-1 {{cast to 'void *' from smaller integer type 'int'}} // purecap-warning@-2 {{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} diff --git a/clang/test/Sema/cheri/cheri-memcap-attr.c b/clang/test/Sema/cheri/cheri-memcap-attr.c index 5fe3b3946088..0070a7e1fb11 100644 --- a/clang/test/Sema/cheri/cheri-memcap-attr.c +++ b/clang/test/Sema/cheri/cheri-memcap-attr.c @@ -40,8 +40,8 @@ __capability int var1; // expected-error{{only applies to pointers}} #ifdef TYPEDEF // expected-no-diagnostics typedef int* intptr; -__capability intptr x; // CHECK-TYPEDEF: line:[[#@LINE]]:1, col:21> col:21 x 'int * __capability' -__capability intptr *y; // CHECK-TYPEDEF:line:[[#@LINE]]:1, col:22> col:22 y 'int * __capability *' +__capability intptr x; // CHECK-TYPEDEF: line:[[#@LINE]]:1, col:21> col:21 x 'intptr __capability':'int * __capability' +__capability intptr *y; // CHECK-TYPEDEF: line:[[#@LINE]]:1, col:22> col:22 y 'intptr __capability *' #endif #ifdef LIST diff --git a/clang/test/Sema/cheri/init-list-narrowing.c b/clang/test/Sema/cheri/init-list-narrowing.c index b51c438a76c1..2b54c70fbc31 100644 --- a/clang/test/Sema/cheri/init-list-narrowing.c +++ b/clang/test/Sema/cheri/init-list-narrowing.c @@ -12,53 +12,53 @@ extern char foo[]; struct { int x; } ints[] = { - {(void *)0}, - // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} - // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} - // expected-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} - {(void *)42}, - // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} - // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __attribute__((cheri_no_provenance))'}} - {(void *)((long)__INT_MAX__ + 1)}, - // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} - // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __attribute__((cheri_no_provenance))'}} - {(void *)foo}, - // expected-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} - // expected-c-error@-2 {{initializer element is not a compile-time constant}} - // expected-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} - {(void * __capability)0}, - // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))'}} - // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} - {(void * __capability)42}, - // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))'}} - // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability __attribute__((cheri_no_provenance))'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __attribute__((cheri_no_provenance))'}} - {(void * __capability)((long)__INT_MAX__ + 1)}, - // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))'}} - // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability __attribute__((cheri_no_provenance))'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __attribute__((cheri_no_provenance))'}} - {(void * __capability)foo}, - // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability'}} - // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} - {(__intcap)0}, - {(__intcap)42}, - {(__intcap)((long)__INT_MAX__ + 1)}, + {(void *)0}, + // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} + // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} + // expected-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} + {(void *)42}, + // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} + // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} + // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} + // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __attribute__((cheri_no_provenance))'}} + {(void *)((long)__INT_MAX__ + 1)}, + // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} + // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __attribute__((cheri_no_provenance))'}} + // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} + // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __attribute__((cheri_no_provenance))'}} + {(void *)foo}, + // expected-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void *'}} + // expected-c-error@-2 {{initializer element is not a compile-time constant}} + // expected-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void *'}} + {(void *__capability)0}, + // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))'}} + // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))' (aka 'void *')}} + // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability'}} + // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability' (aka 'void *')}} + {(void *__capability)42}, + // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))'}} + // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))' (aka 'void *')}} + // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability __attribute__((cheri_no_provenance))'}} + // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability __attribute__((cheri_no_provenance))' (aka 'void *')}} + {(void *__capability)((long)__INT_MAX__ + 1)}, + // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))'}} + // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability __attribute__((cheri_no_provenance))' (aka 'void *')}} + // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability __attribute__((cheri_no_provenance))'}} + // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability __attribute__((cheri_no_provenance))' (aka 'void *')}} + {(void *__capability)foo}, + // hybrid-c-warning@-1 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability'}} + // purecap-c-warning@-2 {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'void * __capability' (aka 'void *')}} + // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability'}} + // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'int' with an rvalue of type 'void * __capability' (aka 'void *')}} + {(__intcap)0}, + {(__intcap)42}, + {(__intcap)((long)__INT_MAX__ + 1)}, // expected-c-warning@-1 {{implicit conversion from '__intcap __attribute__((cheri_no_provenance))' to 'int' changes value from 2147483648 to -2147483648}} // expected-cxx-error@-2 {{constant expression evaluates to 2147483648 which cannot be narrowed to type 'int'}} // expected-cxx-note@-3 {{insert an explicit cast to silence this issue}} #ifdef __cplusplus - {__null}, - {(__intcap)__null}, + {__null}, + {(__intcap) __null}, #endif }; @@ -98,37 +98,37 @@ struct { struct { void * __capability p; } caps[] = { - {(void *)0}, - // hybrid-cxx-warning@-1 {{converting non-capability type 'void *' to capability type 'void * __capability' without an explicit cast; if this is intended use __cheri_tocap}} - {(void *)42}, - // hybrid-warning@-1 {{converting non-capability type 'void *' to capability type 'void * __capability' without an explicit cast; if this is intended use __cheri_tocap}} - {(void *)((long)__INT_MAX__ + 1)}, - // hybrid-warning@-1 {{converting non-capability type 'void *' to capability type 'void * __capability' without an explicit cast; if this is intended use __cheri_tocap}} - {(void *)foo}, - // hybrid-warning@-1 {{converting non-capability type 'void *' to capability type 'void * __capability' without an explicit cast; if this is intended use __cheri_tocap}} - {(void * __capability)0}, - {(void * __capability)42}, - {(void * __capability)((long)__INT_MAX__ + 1)}, - {(void * __capability)foo}, - {(__intcap)0}, - // hybrid-c-warning@-1 {{expression which evaluates to zero treated as a null pointer constant of type 'void * __capability'}} - // purecap-c-warning@-2 {{expression which evaluates to zero treated as a null pointer constant of type 'void *'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'void * __capability' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'void *' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} - {(__intcap)42}, - // hybrid-c-warning@-1 {{incompatible integer to pointer conversion initializing 'void * __capability' with an expression of type '__intcap __attribute__((cheri_no_provenance))'}} - // purecap-c-warning@-2 {{incompatible integer to pointer conversion initializing 'void *' with an expression of type '__intcap __attribute__((cheri_no_provenance))'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'void * __capability' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'void *' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} - {(__intcap)((long)__INT_MAX__ + 1)}, - // hybrid-c-warning@-1 {{incompatible integer to pointer conversion initializing 'void * __capability' with an expression of type '__intcap __attribute__((cheri_no_provenance))'}} - // purecap-c-warning@-2 {{incompatible integer to pointer conversion initializing 'void *' with an expression of type '__intcap __attribute__((cheri_no_provenance))'}} - // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'void * __capability' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} - // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'void *' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} + {(void *)0}, + // hybrid-cxx-warning@-1 {{converting non-capability type 'void *' to capability type 'void * __capability' without an explicit cast; if this is intended use __cheri_tocap}} + {(void *)42}, + // hybrid-warning@-1 {{converting non-capability type 'void *' to capability type 'void * __capability' without an explicit cast; if this is intended use __cheri_tocap}} + {(void *)((long)__INT_MAX__ + 1)}, + // hybrid-warning@-1 {{converting non-capability type 'void *' to capability type 'void * __capability' without an explicit cast; if this is intended use __cheri_tocap}} + {(void *)foo}, + // hybrid-warning@-1 {{converting non-capability type 'void *' to capability type 'void * __capability' without an explicit cast; if this is intended use __cheri_tocap}} + {(void *__capability)0}, + {(void *__capability)42}, + {(void *__capability)((long)__INT_MAX__ + 1)}, + {(void *__capability)foo}, + {(__intcap)0}, + // hybrid-c-warning@-1 {{expression which evaluates to zero treated as a null pointer constant of type 'void * __capability'}} + // purecap-c-warning@-2 {{expression which evaluates to zero treated as a null pointer constant of type 'void * __capability' (aka 'void *')}} + // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'void * __capability' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} + // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'void * __capability' (aka 'void *') with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} + {(__intcap)42}, + // hybrid-c-warning@-1 {{incompatible integer to pointer conversion initializing 'void * __capability' with an expression of type '__intcap __attribute__((cheri_no_provenance))'}} + // purecap-c-warning@-2 {{incompatible integer to pointer conversion initializing 'void * __capability' (aka 'void *') with an expression of type '__intcap __attribute__((cheri_no_provenance))'}} + // hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'void * __capability' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} + // purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'void * __capability' (aka 'void *') with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} + {(__intcap)((long)__INT_MAX__ + 1)}, +// hybrid-c-warning@-1 {{incompatible integer to pointer conversion initializing 'void * __capability' with an expression of type '__intcap __attribute__((cheri_no_provenance))'}} +// purecap-c-warning@-2 {{incompatible integer to pointer conversion initializing 'void * __capability' (aka 'void *') with an expression of type '__intcap __attribute__((cheri_no_provenance))'}} +// hybrid-cxx-error@-3 {{cannot initialize a member subobject of type 'void * __capability' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} +// purecap-cxx-error@-4 {{cannot initialize a member subobject of type 'void * __capability' (aka 'void *') with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} #ifdef __cplusplus - {__null}, - {(__intcap)__null}, - // hybrid-cxx-error@-1 {{cannot initialize a member subobject of type 'void * __capability' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} - // purecap-cxx-error@-2 {{cannot initialize a member subobject of type 'void *' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} + {__null}, + {(__intcap) __null}, +// hybrid-cxx-error@-1 {{cannot initialize a member subobject of type 'void * __capability' with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} +// purecap-cxx-error@-2 {{cannot initialize a member subobject of type 'void * __capability' (aka 'void *') with an rvalue of type '__intcap __attribute__((cheri_no_provenance))'}} #endif }; diff --git a/clang/test/Sema/cheri/union-cast-extension.c b/clang/test/Sema/cheri/union-cast-extension.c index 200535c6d83d..b8b09c368afa 100644 --- a/clang/test/Sema/cheri/union-cast-extension.c +++ b/clang/test/Sema/cheri/union-cast-extension.c @@ -35,7 +35,7 @@ CapIntUnion cap_conversion2(void *b) { InvalidUnion bad_conversion1(void *__capability b) { return (InvalidUnion)b; - // purecap-error@-1{{cast to union type from type 'void *' not present in union}} + // purecap-error@-1{{cast to union type from type 'void * __capability' (aka 'void *') not present in union}} // hybrid-error@-2{{cast to union type from type 'void * __capability' not present in union}} } InvalidUnion bad_conversion2(void *b) { diff --git a/clang/test/Sema/format-strings-cheri.c b/clang/test/Sema/format-strings-cheri.c index 371757ceddf1..bdbf6877cd74 100644 --- a/clang/test/Sema/format-strings-cheri.c +++ b/clang/test/Sema/format-strings-cheri.c @@ -20,15 +20,15 @@ void test_long_pointer(void * __capability p) { printf("%#.4lp", p); printf("%lp", &p); // hybrid-warning@-1{{format specifies type 'void * __capability' but the argument has type 'void * __capability *'}} - // purecap-pedantic-warning@-2{{format specifies type 'void *' but the argument has type 'void **'}} + // purecap-pedantic-warning@-2{{format specifies type 'void * __capability' (aka 'void *') but the argument has type 'void * __capability *' (aka 'void **')}} printf("%lp", (void *)0); // hybrid-warning@-1{{format specifies type 'void * __capability' but the argument has type 'void *'}} printf("%lp", (void **)(void *)0); // hybrid-warning@-1{{format specifies type 'void * __capability' but the argument has type 'void **'}} - // purecap-pedantic-warning@-2{{format specifies type 'void *' but the argument has type 'void ** __attribute__((cheri_no_provenance))'}} + // purecap-pedantic-warning@-2{{format specifies type 'void * __capability' (aka 'void *') but the argument has type 'void ** __attribute__((cheri_no_provenance))'}} printf("%lp", (int *)(void *)0); // hybrid-warning@-1{{format specifies type 'void * __capability' but the argument has type 'int *'}} - // purecap-pedantic-warning@-2{{format specifies type 'void *' but the argument has type 'int * __attribute__((cheri_no_provenance))'}} + // purecap-pedantic-warning@-2{{format specifies type 'void * __capability' (aka 'void *') but the argument has type 'int * __attribute__((cheri_no_provenance))'}} } void test_invalid_length_modifiers(void *p) { diff --git a/clang/test/SemaCXX/cheri/cheri-brace-init.cpp b/clang/test/SemaCXX/cheri/cheri-brace-init.cpp index 2e011875bc86..3928576512f0 100644 --- a/clang/test/SemaCXX/cheri/cheri-brace-init.cpp +++ b/clang/test/SemaCXX/cheri/cheri-brace-init.cpp @@ -14,55 +14,55 @@ struct test { void test_capptr_to_int(void* __capability a) { ptraddr_t v{a}; // hybrid-error@-1 {{cannot initialize a variable of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a variable of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a variable of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void * __capability' (aka 'void *')}} v = ptraddr_t{a}; // hybrid-error@-1 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void * __capability' (aka 'void *')}} ptraddr_t v2 = 0; v2 = {a}; // hybrid-error@-1 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void * __capability' (aka 'void *')}} // NB: Compound literals are a GNU C++ extension so we need a single word alias using __uintcap = unsigned __intcap; __uintcap uc{a}; // hybrid-error@-1 {{cannot initialize a variable of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a variable of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a variable of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void * __capability' (aka 'void *')}} uc = __uintcap{a}; // hybrid-error@-1 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void * __capability' (aka 'void *')}} __uintcap uc2 = 0; uc2 = {a}; // hybrid-error@-1 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void * __capability' (aka 'void *')}} __intcap ic{a}; // hybrid-error@-1 {{cannot initialize a variable of type '__intcap' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a variable of type '__intcap' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a variable of type '__intcap' with an lvalue of type 'void * __capability' (aka 'void *')}} ic = __intcap{a}; // hybrid-error@-1 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void * __capability' (aka 'void *')}} __intcap ic2 = 0; ic2 = {a}; // hybrid-error@-1 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void * __capability' (aka 'void *')}} long l{a}; // hybrid-error@-1 {{cannot initialize a variable of type 'long' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a variable of type 'long' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a variable of type 'long' with an lvalue of type 'void * __capability' (aka 'void *')}} l = long{a}; // hybrid-error@-1 {{cannot initialize a value of type 'long' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'long' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'long' with an lvalue of type 'void * __capability' (aka 'void *')}} long l2 = 0; l2 = {a}; // hybrid-error@-1 {{cannot initialize a value of type 'long' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'long' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'long' with an lvalue of type 'void * __capability' (aka 'void *')}} int i{a}; // hybrid-error@-1 {{cannot initialize a variable of type 'int' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a variable of type 'int' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a variable of type 'int' with an lvalue of type 'void * __capability' (aka 'void *')}} i = int{a}; // hybrid-error@-1 {{cannot initialize a value of type 'int' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'int' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'int' with an lvalue of type 'void * __capability' (aka 'void *')}} int i2 = 0; i2 = {a}; // hybrid-error@-1 {{cannot initialize a value of type 'int' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'int' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'int' with an lvalue of type 'void * __capability' (aka 'void *')}} } void test_uintcap_to_int(unsigned __intcap a) { diff --git a/clang/test/SemaCXX/cheri/cheri-cap-ptr-casts.cpp b/clang/test/SemaCXX/cheri/cheri-cap-ptr-casts.cpp index df1b36b5b3d1..b34aeee81758 100644 --- a/clang/test/SemaCXX/cheri/cheri-cap-ptr-casts.cpp +++ b/clang/test/SemaCXX/cheri/cheri-cap-ptr-casts.cpp @@ -9,12 +9,12 @@ void f() { char * __capability bufp; void (* __capability fp)(); bufp = reinterpret_cast(buf); - // HYBRID-AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'char * __capability' reinterpret_cast {{$}} - // PURECAP-AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'char *' reinterpret_cast {{$}} + // HYBRID-AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'char * __capability':'char * __capability' reinterpret_cast {{$}} + // PURECAP-AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'char * __capability':'char *' reinterpret_cast {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} {{.*}} 'char *' part_of_explicit_cast{{$}} fp = reinterpret_cast(f); - // HYBRID-AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'void (* __capability)()' reinterpret_cast {{$}} - // PURECAP-AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'void (*)()' reinterpret_cast {{$}} + // HYBRID-AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'void (* __capability)()':'void (* __capability)()' reinterpret_cast {{$}} + // PURECAP-AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'void (* __capability)()':'void (*)()' reinterpret_cast {{$}} // AST-NEXT: ImplicitCastExpr {{.*}} {{.*}} 'void (*)()' part_of_explicit_cast{{$}} bufp = static_cast(buf); // hybrid-error@-1 {{static_cast from 'char *' to 'char * __capability' changes capability qualifier}} diff --git a/clang/test/SemaCXX/cheri/cheri-cap-to-int-cast.cpp b/clang/test/SemaCXX/cheri/cheri-cap-to-int-cast.cpp index 8bbe87f8a389..1c48f4c82b28 100644 --- a/clang/test/SemaCXX/cheri/cheri-cap-to-int-cast.cpp +++ b/clang/test/SemaCXX/cheri/cheri-cap-to-int-cast.cpp @@ -34,12 +34,12 @@ void cast_vaddr() { ptraddr_t v = reinterpret_cast(a); v = static_cast(a); // hybrid-error@-1 {{static_cast from 'void * __capability' to 'ptraddr_t' (aka 'unsigned long') is not allowed}} - // purecap-error@-2 {{static_cast from 'void *' to 'ptraddr_t' (aka 'unsigned long') is not allowed}} + // purecap-error@-2 {{static_cast from 'void * __capability' (aka 'void *') to 'ptraddr_t' (aka 'unsigned long') is not allowed}} v = (ptraddr_t)a; v = ptraddr_t(a); v = ptraddr_t{a}; // hybrid-error@-1 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'ptraddr_t' (aka 'unsigned long') with an lvalue of type 'void * __capability' (aka 'void *')}} } void cast_vaddr2() { @@ -47,7 +47,7 @@ void cast_vaddr2() { long __attribute__((memory_address)) v = reinterpret_cast(a); v = static_cast(a); // hybrid-error@-1 {{static_cast from 'void * __capability' to 'long __attribute__((memory_address))' is not allowed}} - // purecap-error@-2 {{static_cast from 'void *' to 'long __attribute__((memory_address))' is not allowed}} + // purecap-error@-2 {{static_cast from 'void * __capability' (aka 'void *') to 'long __attribute__((memory_address))' is not allowed}} v = (long __attribute__((memory_address)))a; // these won't work, need single token for functional/brace-init: // v = long __attribute__((memory_address))(a); @@ -56,26 +56,26 @@ void cast_vaddr2() { __attribute__((memory_address)) long v2 = reinterpret_cast<__attribute__((memory_address)) long>(a); v2 = static_cast<__attribute__((memory_address)) long>(a); // hybrid-error@-1 {{static_cast from 'void * __capability' to 'long __attribute__((memory_address))' is not allowed}} - // purecap-error@-2 {{static_cast from 'void *' to 'long __attribute__((memory_address))' is not allowed}} + // purecap-error@-2 {{static_cast from 'void * __capability' (aka 'void *') to 'long __attribute__((memory_address))' is not allowed}} v2 = (__attribute__((memory_address)) long)a; } void cast_long() { long v = reinterpret_cast(a); // hybrid-warning@-1 {{cast from capability type 'void * __capability' to non-capability, non-address type 'long' is most likely an error}} - // purecap-warning@-2 {{cast from capability type 'void *' to non-capability, non-address type 'long' is most likely an error}} + // purecap-warning@-2 {{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'long' is most likely an error}} v = static_cast(a); // hybrid-error@-1 {{static_cast from 'void * __capability' to 'long' is not allowed}} - // purecap-error@-2 {{static_cast from 'void *' to 'long' is not allowed}} + // purecap-error@-2 {{static_cast from 'void * __capability' (aka 'void *') to 'long' is not allowed}} v = (long)a; // hybrid-warning@-1 {{cast from capability type 'void * __capability' to non-capability, non-address type 'long' is most likely an error}} - // purecap-warning@-2 {{cast from capability type 'void *' to non-capability, non-address type 'long' is most likely an error}} + // purecap-warning@-2 {{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'long' is most likely an error}} v = long(a); // hybrid-warning@-1 {{cast from capability type 'void * __capability' to non-capability, non-address type 'long' is most likely an error}} - // purecap-warning@-2 {{cast from capability type 'void *' to non-capability, non-address type 'long' is most likely an error}} + // purecap-warning@-2 {{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'long' is most likely an error}} v = long{a}; // hybrid-error@-1 {{cannot initialize a value of type 'long' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'long' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'long' with an lvalue of type 'void * __capability' (aka 'void *')}} } // Should cause narrowing errors @@ -83,34 +83,34 @@ void cast_int() { int v = reinterpret_cast(a); // expected-error {{cast from capability to smaller type 'int' loses information}} v = static_cast(a); // hybrid-error@-1 {{static_cast from 'void * __capability' to 'int' is not allowed}} - // purecap-error@-2 {{static_cast from 'void *' to 'int' is not allowed}} + // purecap-error@-2 {{static_cast from 'void * __capability' (aka 'void *') to 'int' is not allowed}} v = (int)a; // expected-error {{cast from capability to smaller type 'int' loses information}} v = int(a); // expected-error {{cast from capability to smaller type 'int' loses information}} v = int{a}; // hybrid-error@-1 {{cannot initialize a value of type 'int' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type 'int' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type 'int' with an lvalue of type 'void * __capability' (aka 'void *')}} } void cast_uintcap() { // AST-LABEL: FunctionDecl {{.+}} cast_uintcap 'void ()' unsigned __intcap v = reinterpret_cast(a); // AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'unsigned __intcap' reinterpret_cast - // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability' - // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability' - // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void *' - // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void *' + // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void * __capability' + // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void * __capability' + // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void *' + // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void *' v = reinterpret_cast(nullptr); // AST: CXXReinterpretCastExpr {{.*}} {{.*}} 'unsigned __intcap __attribute__((cheri_no_provenance))':'unsigned __intcap' reinterpret_cast // AST-NEXT: CXXNullPtrLiteralExpr {{.+}} 'std::nullptr_t' v = static_cast(a); // hybrid-error@-1 {{static_cast from 'void * __capability' to 'unsigned __intcap' is not allowed}} - // purecap-error@-2 {{static_cast from 'void *' to 'unsigned __intcap' is not allowed}} + // purecap-error@-2 {{static_cast from 'void * __capability' (aka 'void *') to 'unsigned __intcap' is not allowed}} v = (unsigned __intcap)a; // AST: CStyleCastExpr {{.*}} {{.*}} 'unsigned __intcap' - // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability' - // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability' - // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void *' - // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void *' + // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void * __capability' + // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void * __capability' + // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void *' + // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void *' // NB: C++ only supports a single word type name for functional casts and // direct list initialisers (GNU C++ supports compound literals for the // latter) so we need to introduce a single word alias for testing (we could @@ -119,44 +119,44 @@ void cast_uintcap() { using __uintcap = unsigned __intcap; v = __uintcap(a); // AST: CXXFunctionalCastExpr {{.*}} {{.*}} '__uintcap':'unsigned __intcap' functional cast to __uintcap - // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability' - // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability' - // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void *' - // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void *' + // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void * __capability' + // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void * __capability' + // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void *' + // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void *' v = __uintcap{a}; // hybrid-error@-1 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type '__uintcap' (aka 'unsigned __intcap') with an lvalue of type 'void * __capability' (aka 'void *')}} } void cast_intcap() { // AST-LABEL: FunctionDecl {{.+}} cast_intcap 'void ()' __intcap v = reinterpret_cast<__intcap>(a); // AST: CXXReinterpretCastExpr {{.*}} {{.*}} '__intcap' reinterpret_cast<__intcap> - // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability' - // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability' - // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void *' - // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void *' + // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void * __capability' + // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void * __capability' + // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void *' + // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void *' v = reinterpret_cast<__intcap>(nullptr); // AST: CXXReinterpretCastExpr {{.*}} {{.*}} '__intcap __attribute__((cheri_no_provenance))':'__intcap' reinterpret_cast<__intcap> // AST-NEXT: CXXNullPtrLiteralExpr {{.+}} 'std::nullptr_t' v = static_cast<__intcap>(a); // hybrid-error@-1 {{static_cast from 'void * __capability' to '__intcap' is not allowed}} - // purecap-error@-2 {{static_cast from 'void *' to '__intcap' is not allowed}} + // purecap-error@-2 {{static_cast from 'void * __capability' (aka 'void *') to '__intcap' is not allowed}} v = (__intcap)a; // AST: CStyleCastExpr {{.*}} {{.*}} '__intcap' - // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability' - // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability' - // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void *' - // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void *' + // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void * __capability' + // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void * __capability' + // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void *' + // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void *' v = __intcap(a); // AST: CXXFunctionalCastExpr {{.*}} {{.*}} '__intcap' functional cast to __intcap - // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability' - // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability' - // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void *' - // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void *' + // HYBRID-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void * __capability' + // HYBRID-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void * __capability' + // PURECAP-AST-NEXT: ImplicitCastExpr {{.+}} 'void * __capability':'void *' + // PURECAP-AST-NEXT: DeclRefExpr {{.+}} 'a' 'void * __capability':'void *' v = __intcap{a}; // hybrid-error@-1 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void * __capability'}} - // purecap-error@-2 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void *'}} + // purecap-error@-2 {{cannot initialize a value of type '__intcap' with an lvalue of type 'void * __capability' (aka 'void *')}} } void cast_to_cap(void) { @@ -224,8 +224,8 @@ void cast_ptr() { // hybrid-error@-1 3 {{cast from capability type 'void * __capability' to non-capability type 'wordp' (aka 'unsigned __intcap *') is most likely an error}} // hybrid-error@-2 {{cannot implicitly or explicitly convert non-capability type 'void * __capability' to unrelated capability type 'wordp' (aka 'unsigned __intcap *')}} // hybrid-error@-3 {{const_cast from 'void * __capability' to 'wordp' (aka 'unsigned __intcap *') is not allowed}} - // purecap-error@-4 {{const_cast from 'void *' to 'wordp' (aka 'unsigned __intcap *') is not allowed}} - // purecap-error@-5 {{cannot initialize a value of type 'wordp' (aka 'unsigned __intcap *') with an lvalue of type 'void *'}} + // purecap-error@-4 {{const_cast from 'void * __capability' (aka 'void *') to 'wordp' (aka 'unsigned __intcap *') is not allowed}} + // purecap-error@-5 {{cannot initialize a value of type 'wordp' (aka 'unsigned __intcap *') with an lvalue of type 'void * __capability' (aka 'void *')}} // expected-error@-6 {{'unsigned __intcap' is not a class}} // hybrid-error@-7 {{static_cast from 'void * __capability' to 'wordp' (aka 'unsigned __intcap *') changes capability qualifier}} diff --git a/clang/test/SemaCXX/cheri/cheri-capability-qualifier-dependent.cpp b/clang/test/SemaCXX/cheri/cheri-capability-qualifier-dependent.cpp index f18ad70a1f57..0252ff5e0ba2 100644 --- a/clang/test/SemaCXX/cheri/cheri-capability-qualifier-dependent.cpp +++ b/clang/test/SemaCXX/cheri/cheri-capability-qualifier-dependent.cpp @@ -41,9 +41,9 @@ T * __capability test_template4(T *p) { T __capability c = (__cheri_tocap T __capability)p; // expected-error@-1 2 {{__capability only applies to pointers; type here is 'void'}} // expected-error@-2 2 {{__capability only applies to pointers; type here is 'int'}} - // expected-error@-3 {{variable has incomplete type 'void'}} - // expected-error@-4 {{cast to incomplete type 'void'}} - // expected-error@-5 {{invalid target type 'int' for __cheri_tocap: target must be a capability}} + // expected-error@-3 {{variable has incomplete type 'void __capability' (aka 'void')}} + // expected-error@-4 {{cast to incomplete type 'void __capability' (aka 'void')}} + // expected-error@-5 {{invalid target type 'int __capability' (aka 'int') for __cheri_tocap: target must be a capability}} return c; // expected-error@-1 {{cannot initialize return object of type 'void ** __capability' with an lvalue of type 'void * __capability'}} } diff --git a/clang/test/SemaCXX/cheri/cheri-int-to-cap-cast.cpp b/clang/test/SemaCXX/cheri/cheri-int-to-cap-cast.cpp index 6cf65bd7e5d4..d66bac13fe7c 100644 --- a/clang/test/SemaCXX/cheri/cheri-int-to-cap-cast.cpp +++ b/clang/test/SemaCXX/cheri/cheri-int-to-cap-cast.cpp @@ -9,13 +9,13 @@ void test_static_cast(int x, long y) { cap = static_cast(x); // hybrid-error@-1 {{cannot cast from type 'int' to pointer type 'void * __capability'}} - // purecap-error@-2 {{cannot cast from type 'int' to pointer type 'void *'}} + // purecap-error@-2 {{cannot cast from type 'int' to pointer type 'void * __capability' (aka 'void *')}} ptr = static_cast(x); // expected-error@-1 {{cannot cast from type 'int' to pointer type 'void *'}} cap = static_cast(y); // hybrid-error@-1 {{cannot cast from type 'long' to pointer type 'void * __capability'}} - // purecap-error@-2 {{cannot cast from type 'long' to pointer type 'void *'}} + // purecap-error@-2 {{cannot cast from type 'long' to pointer type 'void * __capability' (aka 'void *')}} } void test_reinterpret_cast(int x, long y) { @@ -40,13 +40,13 @@ void test_dynamic_cast(int x, long y) { cap = dynamic_cast(x); // hybrid-error@-1 {{cannot use dynamic_cast to convert from 'int' to 'void * __capability'}} - // purecap-error@-2 {{cannot use dynamic_cast to convert from 'int' to 'void *'}} + // purecap-error@-2 {{cannot use dynamic_cast to convert from 'int' to 'void * __capability' (aka 'void *')}} ptr = dynamic_cast(x); // expected-error@-1 {{cannot use dynamic_cast to convert from 'int' to 'void *'}} cap = dynamic_cast(y); // hybrid-error@-1 {{cannot use dynamic_cast to convert from 'long' to 'void * __capability'}} - // purecap-error@-2 {{cannot use dynamic_cast to convert from 'long' to 'void *'}} + // purecap-error@-2 {{cannot use dynamic_cast to convert from 'long' to 'void * __capability' (aka 'void *')}} } template @@ -94,9 +94,9 @@ class TestQualified { // static_cast isn't valid for integer to pointer casts. return static_cast(s); // hybrid-error@-1 {{cannot cast from type 'int' to pointer type 'void * __capability'}} - // purecap-error@-2 {{cannot cast from type 'int' to pointer type 'void *'}} + // purecap-error@-2 {{cannot cast from type 'int' to pointer type 'void * __capability' (aka 'void *')}} // hybrid-error@-3 {{cannot cast from type 'long' to pointer type 'void * __capability'}} - // purecap-error@-4 {{cannot cast from type 'long' to pointer type 'void *'}} + // purecap-error@-4 {{cannot cast from type 'long' to pointer type 'void * __capability' (aka 'void *')}} } T __capability test_reinterpret_cast(S s) { @@ -109,9 +109,9 @@ class TestQualified { // dynamic_cast isn't valid for integer to pointer casts. return dynamic_cast(s); // hybrid-error@-1 {{cannot use dynamic_cast to convert from 'int' to 'void * __capability'}} - // purecap-error@-2 {{cannot use dynamic_cast to convert from 'int' to 'void *'}} + // purecap-error@-2 {{cannot use dynamic_cast to convert from 'int' to 'void * __capability' (aka 'void *')}} // hybrid-error@-3 {{cannot use dynamic_cast to convert from 'long' to 'void * __capability'}} - // purecap-error@-4 {{cannot use dynamic_cast to convert from 'long' to 'void *'}} + // purecap-error@-4 {{cannot use dynamic_cast to convert from 'long' to 'void * __capability' (aka 'void *')}} } }; diff --git a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp index d50f71aa3d8a..ed32065a8904 100644 --- a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp +++ b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp @@ -26,15 +26,17 @@ int foo; int main() { void *CAP x = (int *CAP) & foo; DO_CASTS(ulong, x); - // nohybrid-error@-1 {{static_cast from 'void *' to 'ulong' (aka 'unsigned long') is not allowed}} + // nocheri-error@-1 {{static_cast from 'void *' to 'ulong' (aka 'unsigned long') is not allowed}} // hybrid-error@-2 {{static_cast from 'void * __capability' to 'ulong' (aka 'unsigned long') is not allowed}} - // hybrid-warning@-3 3 {{cast from capability type 'void * __capability' to non-capability, non-address type 'ulong' (aka 'unsigned long') is most likely an error}} - // purecap-warning@-4 3 {{cast from capability type 'void *' to non-capability, non-address type 'ulong' (aka 'unsigned long') is most likely an error}} + // purecap-error@-3 {{static_cast from 'void * __capability' (aka 'void *') to 'ulong' (aka 'unsigned long') is not allowed}} + // hybrid-warning@-4 3 {{cast from capability type 'void * __capability' to non-capability, non-address type 'ulong' (aka 'unsigned long') is most likely an error}} + // purecap-warning@-5 3 {{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'ulong' (aka 'unsigned long') is most likely an error}} DO_CASTS(uint, x); // nocheri-error@-1 3 {{cast from pointer to smaller type 'uint' (aka 'unsigned int') loses information}} // cheri-error@-2 3 {{cast from capability to smaller type 'uint' (aka 'unsigned int') loses information}} - // nohybrid-error@-3 {{static_cast from 'void *' to 'uint' (aka 'unsigned int') is not allowed}} + // nocheri-error@-3 {{static_cast from 'void *' to 'uint' (aka 'unsigned int') is not allowed}} // hybrid-error@-4 {{static_cast from 'void * __capability' to 'uint' (aka 'unsigned int') is not allowed}} + // purecap-error@-5 {{static_cast from 'void * __capability' (aka 'void *') to 'uint' (aka 'unsigned int') is not allowed}} void *nocap = &foo; DO_CASTS(ulong, nocap); // expected-error {{static_cast from 'void *' to 'ulong' (aka 'unsigned long') is not allowed}} @@ -77,7 +79,7 @@ template T offset_set(T x, long off) { return reinterpret_cast(__builtin_cheri_offset_set(reinterpret_cast(x), off)); // hybrid-warning@-1 {{cast from capability type 'void * __capability' to non-capability, non-address type 'long'}} - // purecap-warning@-2 {{cast from capability type 'void *' to non-capability, non-address type 'long'}} + // purecap-warning@-2 {{cast from capability type 'void * __capability' (aka 'void *') to non-capability, non-address type 'long'}} // purecap-warning@-3 {{cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced}} // hybrid-error@-4 {{cast from capability type 'void * __capability' to non-capability type 'x *'}} } diff --git a/clang/test/SemaCXX/cheri/cheri-references.cpp b/clang/test/SemaCXX/cheri/cheri-references.cpp index 5b842e7a2b3f..8a8d114f0ea9 100644 --- a/clang/test/SemaCXX/cheri/cheri-references.cpp +++ b/clang/test/SemaCXX/cheri/cheri-references.cpp @@ -1,8 +1,8 @@ // RUN: %cheri_purecap_cc1 -fsyntax-only -ast-dump %s | FileCheck %s class A { }; -// CHECK: ParmVarDecl {{.*}} {{.*}} {{.*}} used a1 'A &' +// CHECK: ParmVarDecl {{.*}} {{.*}} {{.*}} used a1 'A & __capability':'A &' void f(A& __capability a1) { - // CHECK: VarDecl {{.*}} {{.*}} {{.*}} 'A &' cinit + // CHECK: VarDecl {{.*}} {{.*}} {{.*}} 'A & __capability':'A &' cinit A& __capability a2 = a1; } diff --git a/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp b/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp index 0cb11821bed9..b67f72a72a91 100644 --- a/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp +++ b/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only %s -verify -// RUN: %cheri_cc1 -fsyntax-only %s -verify -// RUN: %cheri_purecap_cc1 -fsyntax-only %s -verify +// RUN: %clang_cc1 -fsyntax-only %s -verify=expected,nocheri +// RUN: %cheri_cc1 -fsyntax-only %s -verify=expected,hybrid +// RUN: %cheri_purecap_cc1 -fsyntax-only %s -verify=expected,purecap #if !__has_feature(capabilities) #define __capability #endif @@ -9,16 +9,28 @@ template class b { public: int *__capability constcast(b d) { - return const_cast(d); // expected-error-re{{const_cast from 'b' to 'int *{{( __capability)?}}' is not allowed}} + return const_cast(d); + // nocheri-error@-1{{const_cast from 'b' to 'int *' is not allowed}} + // hybrid-error@-2{{const_cast from 'b' to 'int * __capability' is not allowed}} + // purecap-error@-3{{const_cast from 'b' to 'int * __capability' (aka 'int *') is not allowed}} } int *__capability staticcast(b d) { - return static_cast(d); // expected-error-re{{cannot cast from type 'b' to pointer type 'int *{{( __capability)?}}'}} + return static_cast(d); + // nocheri-error@-1{{cannot cast from type 'b' to pointer type 'int *'}} + // hybrid-error@-2{{cannot cast from type 'b' to pointer type 'int * __capability'}} + // purecap-error@-3{{cannot cast from type 'b' to pointer type 'int * __capability' (aka 'int *')}} } int *__capability reinterpretcast(b d) { - return reinterpret_cast(d); // expected-error-re{{reinterpret_cast from 'b' to 'int *{{( __capability)?}}' is not allowed}} + return reinterpret_cast(d); + // nocheri-error@-1{{reinterpret_cast from 'b' to 'int *' is not allowed}} + // hybrid-error@-2{{reinterpret_cast from 'b' to 'int * __capability' is not allowed}} + // purecap-error@-3{{reinterpret_cast from 'b' to 'int * __capability' (aka 'int *') is not allowed}} } int *__capability ccast(b d) { - return (int *__capability)(d); // expected-error-re{{cannot cast from type 'b' to pointer type 'int *{{( __capability)?}}'}} + return (int *__capability)(d); + // nocheri-error@-1{{cannot cast from type 'b' to pointer type 'int *'}} + // hybrid-error@-2{{cannot cast from type 'b' to pointer type 'int * __capability'}} + // purecap-error@-3{{cannot cast from type 'b' to pointer type 'int * __capability' (aka 'int *')}} } }; diff --git a/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp b/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp index 6e2b7296d73f..af5e37491930 100644 --- a/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp +++ b/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp @@ -1,11 +1,11 @@ /// Check implicit conversions between capability an non-capability are no permitted in returns -// RUN: %clang_cc1 -Wcheri-pointer-conversion -verify=cxx,expected,nocheri -fsyntax-only %s -// RUN: %cheri_cc1 -Wcheri-pointer-conversion -verify=cxx,expected,hybrid -fsyntax-only %s -// RUN: %cheri_purecap_cc1 -Wcheri-pointer-conversion -verify=cxx,expected,purecap -fsyntax-only %s +// RUN: %clang_cc1 -Wcheri-pointer-conversion -verify=cxx,nocheri,nocheri-cxx -fsyntax-only %s +// RUN: %cheri_cc1 -Wcheri-pointer-conversion -verify=cxx,hybrid,hybrid-cxx -fsyntax-only %s +// RUN: %cheri_purecap_cc1 -Wcheri-pointer-conversion -verify=cxx,purecap,purecap-cxx -fsyntax-only %s /// Also check when compiling C: -// RUN: %clang_cc1 -Wall -Wcheri-pointer-conversion -verify=c,expected,nocheri,nocheri-c -x c -fsyntax-only %s -// RUN: %cheri_cc1 -Wall -Wcheri-pointer-conversion -verify=c,expected,hybrid,hybrid-c -x c -fsyntax-only %s -// RUN: %cheri_purecap_cc1 -Wall -Wcheri-pointer-conversion -verify=c,expected,purecap,purecap-c -x c -fsyntax-only %s +// RUN: %clang_cc1 -Wall -Wcheri-pointer-conversion -verify=c,nocheri,nocheri-c -x c -fsyntax-only %s +// RUN: %cheri_cc1 -Wall -Wcheri-pointer-conversion -verify=c,hybrid,hybrid-c -x c -fsyntax-only %s +// RUN: %cheri_purecap_cc1 -Wall -Wcheri-pointer-conversion -verify=c,purecap,purecap-c -x c -fsyntax-only %s #if __has_feature(capabilities) typedef unsigned __intcap uintcap_t; @@ -23,9 +23,13 @@ void *cast_long_to_intptr_implicit(unsigned long l) { void *__capability cast_long_to_capptr_implicit(unsigned long l) { return l; - // cxx-error-re@-1{{cannot initialize return object of type 'void *{{( __capability)?}}' with an lvalue of type 'unsigned long'}} + // nocheri-cxx-error@-1{{cannot initialize return object of type 'void *' with an lvalue of type 'unsigned long'}} + // hybrid-cxx-error@-2{{cannot initialize return object of type 'void * __capability' with an lvalue of type 'unsigned long'}} + // purecap-cxx-error@-3{{cannot initialize return object of type 'void * __capability' (aka 'void *') with an lvalue of type 'unsigned long'}} // C allows this behaviour, but warns by default - // c-warning-re@-3{{incompatible integer to pointer conversion returning 'unsigned long' from a function with result type 'void *{{( __capability)?}}'}} + // nocheri-c-warning@-5{{incompatible integer to pointer conversion returning 'unsigned long' from a function with result type 'void *'}} + // hybrid-c-warning@-6{{incompatible integer to pointer conversion returning 'unsigned long' from a function with result type 'void * __capability'}} + // purecap-c-warning@-7{{incompatible integer to pointer conversion returning 'unsigned long' from a function with result type 'void * __capability' (aka 'void *')}} // FIXME: should warn in purecap mode about lack of provenance } @@ -38,9 +42,11 @@ void *cast_uintcap_to_intptr_implicit(uintcap_t cap) { void *__capability cast_uintcap_to_capptr_implicit(uintcap_t cap) { return cap; - // cxx-error-re@-1{{cannot initialize return object of type 'void *{{( __capability)?}}' with an lvalue of type 'uintcap_t'}} + // nocheri-cxx-error@-1{{cannot initialize return object of type 'void *' with an lvalue of type 'uintcap_t'}} + // hybrid-cxx-error@-2{{cannot initialize return object of type 'void * __capability' with an lvalue of type 'uintcap_t'}} + // purecap-cxx-error@-3{{cannot initialize return object of type 'void * __capability' (aka 'void *') with an lvalue of type 'uintcap_t'}} // C allows this behaviour, but warns by default - // c-warning-re@-3{{incompatible integer to pointer conversion returning 'uintcap_t' (aka 'unsigned {{(long|__intcap)}}') from a function with result type 'void *{{( __capability)?}}'}} + // c-warning-re@-5{{incompatible integer to pointer conversion returning 'uintcap_t' (aka 'unsigned {{(long|__intcap)}}') from a function with result type 'void *{{( __capability)?}}'}} } void *cast_capptr_to_intptr_implicit(void *__capability cap) { diff --git a/clang/test/SemaCXX/cheri/polymorphic-builtins.cpp b/clang/test/SemaCXX/cheri/polymorphic-builtins.cpp index 69327d2ea280..f0ed5198586f 100644 --- a/clang/test/SemaCXX/cheri/polymorphic-builtins.cpp +++ b/clang/test/SemaCXX/cheri/polymorphic-builtins.cpp @@ -108,7 +108,7 @@ void test_buildcap(struct Incomplete *__capability authcap, unsigned __intcap ub static_assert(__is_same(__typeof__(__builtin_cheri_cap_build(authcap, ubits)), void *__capability), ""); // okay static_assert(__is_same(__typeof__(__builtin_cheri_cap_build(authcap, sbits)), void *__capability), ""); // okay static_assert(__is_same(__typeof__(__builtin_cheri_cap_build(authcap, charpbits)), void *__capability), ""); - // purecap-error@-1{{used type 'char *' where integer is required}} + // purecap-error@-1{{used type 'char * __capability' (aka 'char *') where integer is required}} // hybrid-error@-2{{used type 'char * __capability' where integer is required}} } @@ -210,7 +210,7 @@ void cap_from_pointer(struct Incomplete *__capability authcap, const int *intege static_assert(__is_same(__typeof__(__builtin_cheri_cap_from_pointer(authcap, integerptr)), const int *__capability), ""); // purecap-error@-1{{used type 'const int *' where integer is required}} (void)__builtin_cheri_cap_from_pointer(authcap, capptr); - // purecap-error@-1{{used type 'const int *' where integer is required}} + // purecap-error@-1{{used type 'const int * __capability' (aka 'const int *') where integer is required}} // hybrid-error@-2{{operand of type 'const int * __capability' where arithmetic or pointer type is required}} // authorizing cap must be a capability: diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 70042e53c717..c32f47fc4ad0 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1672,6 +1672,11 @@ bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) { return Visit(TL.getModifiedLoc()); } +bool CursorVisitor::VisitPointerInterpretationTypeLoc( + PointerInterpretationTypeLoc TL) { + return Visit(TL.getModifiedLoc()); +} + bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType) { if (!SkipResultType && Visit(TL.getReturnLoc()))