From 4d71789ba63387d8f5a34dd38abf047a6d1c4569 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Sat, 2 Sep 2023 23:33:46 +0100 Subject: [PATCH] [clang] Extend pointer interpretation handling to track explicitness We need a new type like DependentPointerType for non-dependent contexts that can track __capability applied to things like typeof(...) in order to have a corresponding TypeLoc for the qualifier, otherwise things like TypeSpecLocFiller get out of sync and, in some cases assert (in other cases silently use the wrong DeclSpec). However, this then exposes the fact TypePrinter's PrintingPolicy's SuppressCapabilityQualifier isn't always able to be set to the right value (e.g. when printing out a reinterpret_cast to the user, or when dumping the AST), and so we end up with redundant __capability qualifiers appearing for purecap code in some cases, and so we need to track alongside the pointer interpretation whether it was explicit (which also needs care to ensure it doesn't mess with canonicalisation). Whilst the output is now noisier in cases where __capability is used in purecap code, this is more faithful to the source. The churn in the AST output due to __capability in the source always being sugar is an unfortunate side-effect, but this should disappear if https://github.com/llvm/llvm-project/pull/65214 is merged. Fixes https://github.com/CTSRD-CHERI/llvm-project/issues/710 --- clang/include/clang/AST/ASTContext.h | 101 +++--- clang/include/clang/AST/ASTNodeTraverser.h | 6 + clang/include/clang/AST/Expr.h | 11 +- clang/include/clang/AST/PrettyPrinter.h | 4 - clang/include/clang/AST/PropertiesBase.td | 1 + clang/include/clang/AST/RecursiveASTVisitor.h | 6 + clang/include/clang/AST/Type.h | 311 +++++++++++++----- clang/include/clang/AST/TypeLoc.h | 36 ++ clang/include/clang/AST/TypeProperties.td | 60 +++- clang/include/clang/Basic/TypeNodes.td | 1 + clang/include/clang/Sema/Sema.h | 36 +- .../clang/Serialization/TypeBitCodes.def | 1 + clang/lib/AST/ASTContext.cpp | 241 ++++++++------ clang/lib/AST/ASTDiagnostic.cpp | 29 +- clang/lib/AST/ASTImporter.cpp | 45 ++- clang/lib/AST/ASTStructuralEquivalence.cpp | 12 + clang/lib/AST/Expr.cpp | 80 ++--- clang/lib/AST/FormatString.cpp | 28 +- clang/lib/AST/ItaniumMangle.cpp | 1 + clang/lib/AST/QualTypeNames.cpp | 14 +- clang/lib/AST/Type.cpp | 153 +++++---- clang/lib/AST/TypeLoc.cpp | 4 + clang/lib/AST/TypePrinter.cpp | 77 +++-- clang/lib/CodeGen/CGAtomic.cpp | 6 +- clang/lib/CodeGen/CGDebugInfo.cpp | 4 + clang/lib/CodeGen/CodeGenFunction.cpp | 1 + clang/lib/Parse/ParsePragma.cpp | 20 +- clang/lib/Sema/Sema.cpp | 8 +- clang/lib/Sema/SemaAttr.cpp | 4 - clang/lib/Sema/SemaCast.cpp | 3 +- clang/lib/Sema/SemaChecking.cpp | 26 +- clang/lib/Sema/SemaDecl.cpp | 17 +- clang/lib/Sema/SemaExpr.cpp | 67 ++-- clang/lib/Sema/SemaExprCXX.cpp | 33 +- clang/lib/Sema/SemaOverload.cpp | 12 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 + clang/lib/Sema/SemaType.cpp | 105 ++++-- clang/lib/Sema/TreeTransform.h | 225 +++++++------ clang/lib/Serialization/ASTReader.cpp | 5 + clang/lib/Serialization/ASTWriter.cpp | 7 + clang/test/CodeGen/cheri/cheri-ctofromint.c | 4 +- clang/test/CodeGen/cheri/convert-cap-to-int.c | 26 +- clang/test/CodeGen/cheri/convert-int-to-cap.c | 22 +- clang/test/CodeGen/cheri/global-capinit.c | 40 +-- .../cheri/subobject-bounds-addrof-array.c | 2 +- .../cheri/subobject-bounds-addrof-opt-out.c | 16 +- .../CodeGen/cheri/subobject-bounds-addrof.c | 4 +- clang/test/CodeGen/cheri/warn-ctoptr.c | 2 +- .../cheri/cheri-reference-member-size.cpp | 4 +- .../cheri/cheri-subclass-member.cpp | 4 +- .../cheri/dependent-cheri-casts.cpp | 4 +- .../cheri/reference-bounds-deref.cpp | 2 +- .../Sema/cheri/cheri-cap-offset-addr-casts.c | 23 +- clang/test/Sema/cheri/cheri-cap-ptr-casts.c | 65 ++-- clang/test/Sema/cheri/cheri-cap-to-int-cast.c | 30 +- .../cheri-capability-qualifier-declspec.c | 5 - clang/test/Sema/cheri/cheri-int-to-cap-cast.c | 13 +- clang/test/Sema/cheri/cheri-memcap-attr.c | 4 +- clang/test/Sema/cheri/init-list-narrowing.c | 148 ++++----- clang/test/Sema/cheri/union-cast-extension.c | 2 +- clang/test/Sema/format-strings-cheri.c | 6 +- clang/test/SemaCXX/cheri/cheri-brace-init.cpp | 30 +- .../SemaCXX/cheri/cheri-cap-ptr-casts.cpp | 8 +- .../SemaCXX/cheri/cheri-cap-to-int-cast.cpp | 82 ++--- .../cheri-capability-qualifier-dependent.cpp | 6 +- .../SemaCXX/cheri/cheri-int-to-cap-cast.cpp | 16 +- .../test/SemaCXX/cheri/cheri-pointer-cast.cpp | 12 +- clang/test/SemaCXX/cheri/cheri-references.cpp | 4 +- .../SemaCXX/cheri/dependent-cast-crash.cpp | 26 +- .../implicit-cap-conversion-return-value.cpp | 26 +- .../SemaCXX/cheri/polymorphic-builtins.cpp | 4 +- clang/tools/libclang/CIndex.cpp | 5 + 72 files changed, 1516 insertions(+), 935 deletions(-) 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()))