llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Akira Hatanaka (ahatanak) <details> <summary>Changes</summary> The qualifier allows programmer to directly control how pointers are signed when they are stored in a particular variable. The qualifier takes three arguments: the signing key, a flag specifying whether address discrimination should be used, and a non-negative integer that is used for additional discrimination. ``` typedef void (*my_callback)(const void*); my_callback __ptrauth(ptrauth_key_process_dependent_code, 1, 0xe27a) callback; ``` Co-Authored-By: John McCall rjmccall@<!-- -->apple.com --- Patch is 149.93 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/100830.diff 45 Files Affected: - (modified) clang/docs/PointerAuthentication.rst (+46) - (modified) clang/include/clang/AST/Type.h (+17-4) - (modified) clang/include/clang/Basic/Attr.td (+8) - (modified) clang/include/clang/Basic/AttrDocs.td (+28) - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+44-2) - (modified) clang/include/clang/Basic/Features.def (+1) - (modified) clang/include/clang/Basic/TokenKinds.def (+1) - (modified) clang/include/clang/Parse/Parser.h (+2) - (modified) clang/include/clang/Sema/Sema.h (+11) - (modified) clang/lib/AST/ASTContext.cpp (+1) - (modified) clang/lib/AST/DeclCXX.cpp (+27) - (modified) clang/lib/AST/ItaniumMangle.cpp (+20) - (modified) clang/lib/AST/TypePrinter.cpp (+40) - (modified) clang/lib/CodeGen/CGClass.cpp (+3) - (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+17-2) - (modified) clang/lib/CodeGen/CGDecl.cpp (+9-3) - (modified) clang/lib/CodeGen/CGExpr.cpp (+59-2) - (modified) clang/lib/CodeGen/CGExprConstant.cpp (+21-3) - (modified) clang/lib/CodeGen/CGExprScalar.cpp (+67) - (modified) clang/lib/CodeGen/CGPointerAuth.cpp (+130) - (modified) clang/lib/CodeGen/CodeGenFunction.h (+20) - (modified) clang/lib/Parse/ParseDecl.cpp (+47) - (modified) clang/lib/Sema/SemaCast.cpp (+15-1) - (modified) clang/lib/Sema/SemaChecking.cpp (+63) - (modified) clang/lib/Sema/SemaDecl.cpp (+13-1) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+37) - (modified) clang/lib/Sema/SemaExpr.cpp (+14) - (modified) clang/lib/Sema/SemaExprCXX.cpp (+5) - (modified) clang/lib/Sema/SemaObjCProperty.cpp (+4) - (modified) clang/lib/Sema/SemaOverload.cpp (+11) - (modified) clang/lib/Sema/SemaType.cpp (+87) - (modified) clang/lib/Sema/TreeTransform.h (+11) - (modified) clang/test/AST/ast-dump-ptrauth-json.cpp (+2) - (added) clang/test/CodeGen/ptrauth-debuginfo.c (+32) - (added) clang/test/CodeGen/ptrauth-qualifier-function.c (+132) - (added) clang/test/CodeGen/ptrauth-qualifier-loadstore.c (+744) - (added) clang/test/CodeGen/ptrauth-qualifier.c (+87) - (added) clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp (+167) - (added) clang/test/CodeGenObjCXX/ptrauth-struct-cxx-abi.mm (+35) - (modified) clang/test/Preprocessor/ptrauth_feature.c (+8) - (added) clang/test/Sema/ptrauth-atomic-ops.c (+117) - (added) clang/test/Sema/ptrauth-qualifier.c (+84) - (added) clang/test/SemaCXX/ptrauth-qualifier.cpp (+141) - (added) clang/test/SemaCXX/ptrauth-template-parameters.cpp (+20) - (added) clang/test/SemaObjC/ptrauth-qualifier.m (+55) ``````````diff diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst index 68674f318c84f..41818d43ac687 100644 --- a/clang/docs/PointerAuthentication.rst +++ b/clang/docs/PointerAuthentication.rst @@ -280,6 +280,52 @@ a number of different tests. normal interface. This may be true even on targets where pointer authentication is not enabled by default. +__ptrauth Qualifier +^^^^^^^^^^^^^^^^^^^ + +``__ptrauth(key, address, discriminator)`` is an extended type +qualifier which causes so-qualified objects to hold pointers signed using the +specified schema rather than the default schema for such types. + +In the current implementation in Clang, the qualified type must be a C pointer +type, either to a function or to an object. It currently cannot be an +Objective-C pointer type, a C++ reference type, or a block pointer type; these +restrictions may be lifted in the future. + +The qualifier's operands are as follows: + +- ``key`` - an expression evaluating to a key value from ``<ptrauth.h>``; must + be a constant expression + +- ``address`` - whether to use address diversity (1) or not (0); must be + a constant expression with one of these two values + +- ``discriminator`` - a constant discriminator; must be a constant expression + +See `Discriminators`_ for more information about discriminators. + +Currently the operands must be constant-evaluable even within templates. In the +future this restriction may be lifted to allow value-dependent expressions as +long as they instantiate to a constant expression. + +Consistent with the ordinary C/C++ rule for parameters, top-level ``__ptrauth`` +qualifiers on a parameter (after parameter type adjustment) are ignored when +deriving the type of the function. The parameter will be passed using the +default ABI for the unqualified pointer type. + +If ``x`` is an object of type ``__ptrauth(key, address, discriminator) T``, +then the signing schema of the value stored in ``x`` is a key of ``key`` and +a discriminator determined as follows: + +- if ``address`` is 0, then the discriminator is ``discriminator``; + +- if ``address`` is 1 and ``discriminator`` is 0, then the discriminator is + ``&x``; otherwise + +- if ``address`` is 1 and ``discriminator`` is non-zero, then the discriminator + is ``ptrauth_blend_discriminator(&x, discriminator)``; see + `ptrauth_blend_discriminator`_. + ``<ptrauth.h>`` ~~~~~~~~~~~~~~~ diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 72723c7c56e07..2fb17f352f1b3 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -307,6 +307,12 @@ class PointerAuthQualifier { return Result; } + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const; + + bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; + void print(raw_ostream &OS, const PrintingPolicy &Policy) const; + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Data); } }; @@ -556,7 +562,7 @@ class Qualifiers { bool hasAddressSpace() const { return Mask & AddressSpaceMask; } LangAS getAddressSpace() const { - return static_cast<LangAS>(Mask >> AddressSpaceShift); + return static_cast<LangAS>((Mask & AddressSpaceMask) >> AddressSpaceShift); } bool hasTargetSpecificAddressSpace() const { return isTargetAddressSpace(getAddressSpace()); @@ -815,6 +821,9 @@ class Qualifiers { static_assert(sizeof(PointerAuthQualifier) == sizeof(uint32_t), "PointerAuthQualifier must be 32 bits"); + static constexpr uint64_t PtrAuthShift = 32; + static constexpr uint64_t PtrAuthMask = uint64_t(0xffffffff) << PtrAuthShift; + static constexpr uint64_t UMask = 0x8; static constexpr uint64_t UShift = 3; static constexpr uint64_t GCAttrMask = 0x30; @@ -822,10 +831,8 @@ class Qualifiers { static constexpr uint64_t LifetimeMask = 0x1C0; static constexpr uint64_t LifetimeShift = 6; static constexpr uint64_t AddressSpaceMask = - ~(CVRMask | UMask | GCAttrMask | LifetimeMask); + ~(CVRMask | UMask | GCAttrMask | LifetimeMask | PtrAuthMask); static constexpr uint64_t AddressSpaceShift = 9; - static constexpr uint64_t PtrAuthShift = 32; - static constexpr uint64_t PtrAuthMask = uint64_t(0xffffffff) << PtrAuthShift; }; class QualifiersAndAtomic { @@ -1460,6 +1467,12 @@ class QualType { return getQualifiers().getPointerAuth(); } + bool hasAddressDiscriminatedPointerAuth() const { + if (PointerAuthQualifier ptrauth = getPointerAuth()) + return ptrauth.isAddressDiscriminated(); + return false; + } + enum PrimitiveDefaultInitializeKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 4825979a974d2..f9b447e85707d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3339,6 +3339,14 @@ def ObjCRequiresPropertyDefs : InheritableAttr { let SimpleHandler = 1; } +def PointerAuth : TypeAttr { + let Spellings = [CustomKeyword<"__ptrauth">]; + let Args = [IntArgument<"Key">, + BoolArgument<"AddressDiscriminated", 1>, + IntArgument<"ExtraDiscriminator", 1>]; + let Documentation = [PtrAuthDocs]; +} + def Unused : InheritableAttr { let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">, C23<"", "maybe_unused", 202106>]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 99738812c8157..e7b990a2abb8c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1758,6 +1758,34 @@ Also see the documentation for `@available }]; } +def PtrAuthDocs : Documentation { + let Category = DocCatVariable; + let Heading = "__ptrauth, __ptrauth_restricted_intptr"; + let Content = [{ +The ``__ptrauth`` qualifier allows the programmer to directly control +how pointers are signed when they are stored in a particular variable. +This can be used to strengthen the default protections of pointer +authentication and make it more difficult for an attacker to escalate +an ability to alter memory into full control of a process. + +.. code-block:: c + + #include <ptrauth.h> + + typedef void (*my_callback)(const void*); + my_callback __ptrauth(ptrauth_key_process_dependent_code, 1, 0xe27a) callback; + +The first argument to ``__ptrauth`` is the name of the signing key. +Valid key names for the target are defined in ``<ptrauth.h>``. + +The second argument to ``__ptrauth`` is a flag (0 or 1) specifying whether +the object should use address discrimination. + +The third argument to ``__ptrauth`` is a small non-negative integer +which allows additional discrimination between objects. + }]; +} + def ExternalSourceSymbolDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 810abe4f23e31..db07874ffcbbf 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -956,6 +956,25 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error< "%select{subtraction|addition}0 of address-of-label expressions is not " "supported with ptrauth indirect gotos">; +// __ptrauth qualifier +def err_ptrauth_qualifier_invalid : Error< + "%select{return types|parameter types|properties}2 may not be qualified with %select{__ptrauth|__ptrauth_restricted_intptr}1; type is %0">; +def err_ptrauth_qualifier_cast : Error< + "cast types may not be qualified with __ptrauth; type is %0">; +def err_ptrauth_qualifier_nonpointer : Error< + "__ptrauth qualifier may only be applied to pointer types; type here is %0">; +def err_ptrauth_qualifier_redundant : Error< + "type %0 is already %1-qualified">; +def err_ptrauth_qualifier_bad_arg_count : Error< + "%0 qualifier must take between 1 and 3 arguments">; +def err_ptrauth_arg_not_ice : Error< + "argument to __ptrauth must be an integer constant expression">; +def err_ptrauth_address_discrimination_invalid : Error< + "address discrimination flag for __ptrauth must be 0 or 1; value is %0">; +def err_ptrauth_extra_discriminator_invalid : Error< + "extra discriminator for __ptrauth must be between " + "0 and %1; value is %0">; + /// main() // static main() is not an error in C, just in C++. def warn_static_main : Warning<"'main' should not be declared static">, @@ -3870,7 +3889,8 @@ def note_cannot_use_trivial_abi_reason : Note< "its copy constructors and move constructors are all deleted|" "it is polymorphic|" "it has a base of a non-trivial class type|it has a virtual base|" - "it has a __weak field|it has a field of a non-trivial class type}1">; + "it has a __weak field|it has a field of a non-trivial class type|" + "it has an address-discriminated __ptrauth field}1">; // Availability attribute def warn_availability_unknown_platform : Warning< @@ -4927,6 +4947,10 @@ def note_ovl_candidate_bad_ownership : Note< "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}4 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" "__autoreleasing}5 ownership">; +def note_ovl_candidate_bad_ptrauth : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%ordinal8 argument (%3) has %select{no ptrauth|%5}4 qualifier," + " but parameter has %select{no ptrauth|%7}6 qualifier">; def note_ovl_candidate_bad_cvr_this : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " "'this' argument has type %3, but method is not marked " @@ -6005,7 +6029,7 @@ def note_deleted_special_member_class_subobject : Note< "%select{default|corresponding|default|default|default}4 constructor}0|" "destructor}5" "%select{||s||}4" - "|is an ObjC pointer}6">; + "|is an ObjC pointer|has an address-discriminated ptrauth qualifier}6">; def note_deleted_default_ctor_uninit_field : Note< "%select{default constructor of|constructor inherited by}0 " "%1 is implicitly deleted because field %2 of " @@ -8811,6 +8835,19 @@ def err_typecheck_incompatible_ownership : Error< "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " changes retain/release properties of pointer">; +def err_typecheck_incompatible_ptrauth : Error< + "%select{%diff{assigning $ to $|assigning to different types}1,0" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + " changes pointer-authentication of pointee type">; def err_typecheck_comparison_of_distinct_blocks : Error< "comparison of distinct block types%diff{ ($ and $)|}0,1">; @@ -8939,6 +8976,9 @@ def err_atomic_op_needs_non_const_atomic : Error< def err_atomic_op_needs_non_const_pointer : Error< "address argument to atomic operation must be a pointer to non-const " "type (%0 invalid)">; +def err_atomic_op_needs_non_address_discriminated_pointer : Error< + "address argument to %select{atomic|__sync}0 operation must be a pointer to a non address discriminated " + "type (%1 invalid)">; def err_atomic_op_needs_trivial_copy : Error< "address argument to atomic operation must be a pointer to a " "trivially-copyable type (%0 invalid)">; @@ -9205,6 +9245,8 @@ def ext_typecheck_cond_pointer_integer_mismatch : ExtWarn< "pointer/integer type mismatch in conditional expression" "%diff{ ($ and $)|}0,1">, InGroup<DiagGroup<"conditional-type-mismatch">>; +def err_typecheck_cond_incompatible_ptrauth : Error< + "__ptrauth qualification mismatch%diff{ ($ and $)|}0,1">; def err_typecheck_choose_expr_requires_constant : Error< "'__builtin_choose_expr' requires a constant expression">; def warn_unused_expr : Warning<"expression result unused">, diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index dc71ef8f98692..6853a7969e929 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -104,6 +104,7 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics) +FEATURE(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics) FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls) FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns) FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 8c54661e65cf4..68a214452e28b 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -346,6 +346,7 @@ KEYWORD(_Thread_local , KEYALL) KEYWORD(__func__ , KEYALL) KEYWORD(__objc_yes , KEYALL) KEYWORD(__objc_no , KEYALL) +KEYWORD(__ptrauth , KEYALL) // C++ 2.11p1: Keywords. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 35bb1a19d40f0..e3049914289bd 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3151,6 +3151,8 @@ class Parser : public CodeCompletionHandler { SourceLocation *endLoc = nullptr); ExprResult ParseExtIntegerArgument(); + void ParsePtrauthQualifier(ParsedAttributes &Attrs); + VirtSpecifiers::Specifier isCXX11VirtSpecifier(const Token &Tok) const; VirtSpecifiers::Specifier isCXX11VirtSpecifier() const { return isCXX11VirtSpecifier(Tok); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7bfdaaae45a93..673862e4711a4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3460,6 +3460,17 @@ class Sema final : public SemaBase { bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key); + enum PointerAuthDiscArgKind { + // Address discrimination argument of __ptrauth. + PADAK_AddrDiscPtrAuth, + + // Extra discriminator argument of __ptrauth. + PADAK_ExtraDiscPtrAuth, + }; + + bool checkPointerAuthDiscriminatorArg(Expr *Arg, PointerAuthDiscArgKind Kind, + unsigned &IntVal); + /// Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. void DiagnoseFunctionSpecifiers(const DeclSpec &DS); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a465cdfcf3c89..c1dc730eaa2d5 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11046,6 +11046,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || LQuals.getAddressSpace() != RQuals.getAddressSpace() || LQuals.getObjCLifetime() != RQuals.getObjCLifetime() || + !LQuals.getPointerAuth().isEquivalent(RQuals.getPointerAuth()) || LQuals.hasUnaligned() != RQuals.hasUnaligned()) return {}; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index b573c2713a3aa..c2c550076ea07 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1072,6 +1072,33 @@ void CXXRecordDecl::addedMember(Decl *D) { } else if (!T.isCXX98PODType(Context)) data().PlainOldData = false; + // If a class has an address-discriminated signed pointer member, it is a + // non-POD type and its copy constructor, move constructor, copy assignment + // operator, move assignment operator are non-trivial. + if (PointerAuthQualifier Q = T.getPointerAuth()) { + if (Q.isAddressDiscriminated()) { + struct DefinitionData &Data = data(); + Data.PlainOldData = false; + Data.HasTrivialSpecialMembers &= + ~(SMF_CopyConstructor | SMF_MoveConstructor | SMF_CopyAssignment | + SMF_MoveAssignment); + setArgPassingRestrictions(RecordArgPassingKind::CanNeverPassInRegs); + + // Copy/move constructors/assignment operators of a union are deleted by + // default if it has an address-discriminated ptrauth field. + if (isUnion()) { + data().DefaultedCopyConstructorIsDeleted = true; + data().DefaultedMoveConstructorIsDeleted = true; + data().DefaultedCopyAssignmentIsDeleted = true; + data().DefaultedMoveAssignmentIsDeleted = true; + data().NeedOverloadResolutionForCopyConstructor = true; + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForCopyAssignment = true; + data().NeedOverloadResolutionForMoveAssignment = true; + } + } + } + if (T->isReferenceType()) { if (!Field->hasInClassInitializer()) data().HasUninitializedReferenceMember = true; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index d46d621d4c7d4..0e95517bfa424 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2822,6 +2822,26 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp if (Quals.hasUnaligned()) mangleVendorQualifier("__unaligned"); + // __ptrauth. Note that this is parameterized. + if (PointerAuthQualifier PtrAuth = Quals.getPointerAuth()) { + mangleVendorQualifier("__ptrauth"); + // For now, since we only allow non-dependent arguments, we can just + // inline the mangling of those arguments as literals. We treat the + // key and extra-discriminator arguments as 'unsigned int' and the + // address-discriminated argument as 'bool'. + Out << "I" + "Lj" + << PtrAuth.getKey() + << "E" + "Lb" + << unsigned(PtrAuth.isAddressDiscriminated()) + << "E" + "Lj" + << PtrAuth.getExtraDiscriminator() + << "E" + "E"; + } + // Remaining ARC ownership qualifiers. switch (Quals.getObjCLifetime()) { case Qualifiers::OCL_None: diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ffec3ef9d2269..542cf7502e20e 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1950,6 +1950,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::Ptr64: case attr::SPtr: case attr::UPtr: + case attr::PointerAuth: case attr::AddressSpace: case attr::CmseNSCall: case attr::AnnotateType: @@ -2413,6 +2414,33 @@ void clang::printTemplateArgumentList(raw_ostream &OS, printTo(OS, Args, Policy, TPL, /*isPack*/ false, /*parmIndex*/ 0); } +std::string PointerAuthQualifier::getAsString() const { + LangOptions LO; + return getAsString(PrintingPolicy(LO)); +} + +std::string PointerAuthQualifier::getAsString(const PrintingPolicy &P) const { + SmallString<64> Buf; + llvm::raw_svector_ostream StrOS(Buf); + print(StrOS, P); + return StrOS.str().str(); +} + +bool PointerAuthQualifier::isEmptyWhenPrinted(const PrintingPolicy &P) const { + return !isPresent(); +} + +void PointerAuthQualifier::print(raw_ostream &OS, + const PrintingPolicy &P) const { + if (!isPresent()) + return; + + OS << "__ptrauth("; + OS << getKey(); + OS << "," << unsigned(isAddressDiscriminated()) << "," + << getExtraDiscriminator() << ")"; +} + std::string Qualifiers::getAsString() const { LangOptions LO; return getAsString(PrintingPolicy(LO)); @@ -2442,6 +2470,10 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const { if (!(lifetime == Qualifiers::OCL_Strong && Policy.Suppres... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/100830 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits