This feature is currently not supported in the compiler.
To facilitate this we emit a stub version of each kernel
function body with different name mangling scheme, and
replaces the respective kernel call-sites appropriately.
Fixes https://github.com/llvm/llvm-project/issues/60313
D120566 was an earlier attempt made to upstream a solution
for this issue.
---------
Co-authored-by: anikelal <anikelal@amd.com>
This introduces a new class 'UnsignedOrNone', which models a lite
version of `std::optional<unsigned>`, but has the same size as
'unsigned'.
This replaces most uses of `std::optional<unsigned>`, and similar
schemes utilizing 'int' and '-1' as sentinel.
Besides the smaller size advantage, this is simpler to serialize, as its
internal representation is a single unsigned int as well.
Whereas it is UB in terms of the standard to delete an array of objects
via pointer whose static type doesn't match its dynamic type, MSVC
supports an extension allowing to do it.
Aside from array deletion not working correctly in the mentioned case,
currently not having this extension implemented causes clang to generate
code that is not compatible with the code generated by MSVC, because
clang always puts scalar deleting destructor to the vftable. This PR
aims to resolve these problems.
It was reverted due to link time errors in chromium with sanitizer
coverage enabled,
which is fixed by https://github.com/llvm/llvm-project/pull/131929 .
The second commit of this PR also contains a fix for a runtime failure
in chromium reported
in
https://github.com/llvm/llvm-project/pull/126240#issuecomment-2730216384
.
Fixes https://github.com/llvm/llvm-project/issues/19772
C2y adds the `_Countof` operator which returns the number of elements in
an array. As with `sizeof`, `_Countof` either accepts a parenthesized
type name or an expression. Its operand must be (of) an array type. When
passed a constant-size array operand, the operator is a constant
expression which is valid for use as an integer constant expression.
This is being exposed as an extension in earlier C language modes, but
not in C++. C++ already has `std::extent` and `std::size` to cover these
needs, so the operator doesn't seem to get the user enough benefit to
warrant carrying this as an extension.
Fixes#102836
Original PR: #130537
Originally reverted due to revert of dependent commit. Relanding with no
changes.
This changes the MemberPointerType representation to use a
NestedNameSpecifier instead of a Type to represent the base class.
Since the qualifiers are always parsed as nested names, there was an
impedance mismatch when converting these back and forth into types, and
this led to issues in preserving sugar.
The nested names are indeed a better match for these, as the differences
which a QualType can represent cannot be expressed syntatically, and
they represent the use case more exactly, being either dependent or
referring to a CXXRecord, unqualified.
This patch also makes the MemberPointerType able to represent sugar for
a {up/downcast}cast conversion of the base class, although for now the
underlying type is canonical, as preserving the sugar up to that point
requires further work.
As usual, includes a few drive-by fixes in order to make use of the
improvements.
Original PR: #130537
Reland after updating lldb too.
This changes the MemberPointerType representation to use a
NestedNameSpecifier instead of a Type to represent the base class.
Since the qualifiers are always parsed as nested names, there was an
impedance mismatch when converting these back and forth into types, and
this led to issues in preserving sugar.
The nested names are indeed a better match for these, as the differences
which a QualType can represent cannot be expressed syntatically, and
they represent the use case more exactly, being either dependent or
referring to a CXXRecord, unqualified.
This patch also makes the MemberPointerType able to represent sugar for
a {up/downcast}cast conversion of the base class, although for now the
underlying type is canonical, as preserving the sugar up to that point
requires further work.
As usual, includes a few drive-by fixes in order to make use of the
improvements.
This changes the MemberPointerType representation to use a
NestedNameSpecifier instead of a Type to represent the class.
Since the qualifiers are always parsed as nested names, there was an
impedance mismatch when converting these back and forth into types, and
this led to issues in preserving sugar.
The nested names are indeed a better match for these, as the differences
which a QualType can represent cannot be expressed syntactically, and it
also represents the use case more exactly, being either dependent or
referring to a CXXRecord, unqualified.
This patch also makes the MemberPointerType able to represent sugar for
a {up/downcast}cast conversion of the base class, although for now the
underlying type is canonical, as preserving the sugar up to that point
requires further work.
As usual, includes a few drive-by fixes in order to make use of the
improvements, and removing some duplications, for example
CheckBaseClassAccess is deduplicated from across SemaAccess and
SemaCast.
This caused link errors when building with sancov. See comment on the PR.
> Whereas it is UB in terms of the standard to delete an array of objects
> via pointer whose static type doesn't match its dynamic type, MSVC
> supports an extension allowing to do it.
> Aside from array deletion not working correctly in the mentioned case,
> currently not having this extension implemented causes clang to generate
> code that is not compatible with the code generated by MSVC, because
> clang always puts scalar deleting destructor to the vftable. This PR
> aims to resolve these problems.
>
> Fixes https://github.com/llvm/llvm-project/issues/19772
This reverts commit d6942d54f677000cf713d2b0eba57b641452beb4.
Whereas it is UB in terms of the standard to delete an array of objects
via pointer whose static type doesn't match its dynamic type, MSVC
supports an extension allowing to do it.
Aside from array deletion not working correctly in the mentioned case,
currently not having this extension implemented causes clang to generate
code that is not compatible with the code generated by MSVC, because
clang always puts scalar deleting destructor to the vftable. This PR
aims to resolve these problems.
Fixes https://github.com/llvm/llvm-project/issues/19772
This patch adds a function attribute `riscv_vls_cc` for RISCV VLS
calling
convention which takes 0 or 1 argument, the argument is the `ABI_VLEN`
which is the `VLEN` for passing the fixed-vector arguments, it wraps the
argument as a scalable vector(VLA) using the `ABI_VLEN` and uses the
corresponding mechanism to handle it. The range of `ABI_VLEN` is [32,
65536],
if not specified, the default value is 128.
Here is an example of VLS argument passing:
Non-VLS call:
```
void original_call(__attribute__((vector_size(16))) int arg) {}
=>
define void @original_call(i128 noundef %arg) {
entry:
...
ret void
}
```
VLS call:
```
void __attribute__((riscv_vls_cc(256))) vls_call(__attribute__((vector_size(16))) int arg) {}
=>
define riscv_vls_cc void @vls_call(<vscale x 1 x i32> %arg) {
entry:
...
ret void
}
}
```
The first Non-VLS call passes generic vector argument of 16 bytes by
flattened integer.
On the contrary, the VLS call uses `ABI_VLEN=256` which wraps the
vector to <vscale x 1 x i32> where the number of scalable vector
elements
is calaulated by: `ORIG_ELTS * RVV_BITS_PER_BLOCK / ABI_VLEN`.
Note: ORIG_ELTS = Vector Size / Type Size = 128 / 32 = 4.
PsABI PR: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/418
C-API PR: https://github.com/riscv-non-isa/riscv-c-api-doc/pull/68
This merges the functionality of ResolvedUnexpandedPackExpr into
FunctionParmPackExpr. I also added a test to show that
https://github.com/llvm/llvm-project/issues/125103 should be fixed with
this. I put the removal of ResolvedUnexpandedPackExpr in its own commit.
Let me know what you think.
Fixes#125103
If we have +sme but not +sve, we would not set vscale_range on
functions. It should be valid to apply it with the same range with just
+sme, which can help mitigate some performance regressions in cases such
as scalable vector bitcasts (https://godbolt.org/z/exhe4jd8d).
This is an implementation of P1061 Structure Bindings Introduce a Pack
without the ability to use packs outside of templates. There is a couple
of ways the AST could have been sliced so let me know what you think.
The only part of this change that I am unsure of is the
serialization/deserialization stuff. I followed the implementation of
other Exprs, but I do not really know how it is tested. Thank you for
your time considering this.
---------
Co-authored-by: Yanzuo Liu <zwuis@outlook.com>
- The FP8 scalar type (`__mfp8`) was described as a vector type
- The FP8 vector types were described/assumed to have integer element
type (the element type ought to be `__mfp8`)
- Add support for `m` type specifier (denoting `__mfp8`) in
`DecodeTypeFromStr` and create builtin function prototypes using that
specifier, instead of `int8_t`
Reimplement Neon FP8 vector types using attribute `neon_vector_type`
instead of having them as builtin types.
This allows to implement FP8 Neon intrinsics without the need to add
special cases for these types when using `__builtin_shufflevector`
or bitcast (using C-style cast operator) between vectors, both
extensively used in the generated code in `arm_neon.h`.
Similar to arm_sve_vector_bits, the mangling of function types is
implemented as a pseudo template if there are any SME attributes
present, i.e.
`__SME_ATTRS<normal_function_type, sme_state>`
For example, the following function:
`void f(svint8_t (*fn)() __arm_streaming) { fn(); }`
would be mangled as:
`_Z1fP11__SME_ATTRSIFu10__SVInt8_tELj1EE`
See https://github.com/ARM-software/acle/pull/358
Translates `RWBuffer` and `StructuredBuffer` resources buffer types to
DirectX target types `dx.TypedBuffer` and `dx.RawBuffer`.
Includes a change of `HLSLAttributesResourceType` from 'sugar' type to
full canonical type. This is required for codegen and other clang
infrastructure to work property on HLSL resource types.
Fixes#95952 (part 2/2)
Recently, Solaris bootstrap got broken because Solaris uses a
non-standard mangling of `std::tm` and a few others. This was fixed with
a hack in PR #100724. The Solaris ABI requires mangling `std::tm` as
`tm` and similarly for `std::div_t`, `std::ldiv_t`, and `std::lconv`,
which is what this patch implements. The hack needs to stay in place to
allow building with older versions of `clang`.
Tested on `amd64-pc-solaris2.11`, `sparcv9-sun-solaris2.11` (2-stage
builds with both `clang-19` and `gcc-14` as build compiler), and
`x86_64-pc-linux-gnu`.
The 'tile' clause shares quite a bit of the rules with 'collapse', so a
followup patch will add those tests/behaviors. This patch deals with
adding the AST node.
The 'tile' clause takes a series of integer constant expressions, or *.
The asterisk is now represented by a new OpenACCAsteriskSizeExpr node,
else this clause is very similar to others.
Fix#108015
The `mangleNameOrStandardSubstitution` function does not add the RD type
into the substitution, which causes the mangling of the \<base type\> to
be incorrect.
Rename `mangleNameOrStandardSubstitution` to `mangleCXXRecordDecl` and add `Record` as a substitution
Some switch statements require all SVE builtin types to be manually
specified. This patch refactors the SVE_*_TYPE macros so that such code
can be generated during preprocessing.
I've tried to establish a minimal interface that covers all types where
no special information is required and then created a set of macros that
are dedicated to specific datatypes (i.e. int, float).
This patch is groundwork to simplify the changing of SVE tuple types to
become struct based as well as work to support the FP8 ACLE.
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
HLSL output parameters are denoted with the `inout` and `out` keywords
in the function declaration. When an argument to an output parameter is
constructed a temporary value is constructed for the argument.
For `inout` pamameters the argument is initialized via copy-initialization
from the argument lvalue expression to the parameter type. For `out`
parameters the argument is not initialized before the call.
In both cases on return of the function the temporary value is written
back to the argument lvalue expression through an implicit assignment
binary operator with casting as required.
This change introduces a new HLSLOutArgExpr ast node which represents
the output argument behavior. The OutArgExpr has three defined children:
- An OpaqueValueExpr of the argument lvalue expression.
- An OpaqueValueExpr of the copy-initialized parameter.
- A BinaryOpExpr assigning the first with the value of the second.
Fixes#87526
---------
Co-authored-by: Damyan Pepper <damyanp@microsoft.com>
Co-authored-by: John McCall <rjmccall@gmail.com>
Introducing `HLSLAttributedResourceType` - a new type that is similar to
`AttributedType` but with additional data specific to HLSL resources.
`AttributeType` currently only stores an attribute kind and no
additional data from the type attribute parameters. This does not really
work for HLSL resources since its type attributes contain non-boolean
values that need to be retained as well.
For example:
```
template <typename T> class RWBuffer {
__hlsl_resource_t [[hlsl::resource_class(uav)]] [[hlsl::is_rov]] handle;
};
```
The data `HLSLAttributedResourceType` needs to eventually store are:
- resource class (SRV, UAV, CBuffer, Sampler)
- texture dimension(1-3)
- flags is_rov, is_array, is_feedback and is_multisample
- contained type
All of these values except contained type will be stored in
`HLSLAttributedResourceType::Attributes` struct and accessed
individually via the fields. There is also `Data` alias that covers all
of these values as a `unsigned` which is used for hashing and the AST
type serialization.
During type attribute processing all HLSL type attributes will be
validated and collected by SemaHLSL (by
`SemaHLSL::handleResourceTypeAttr`) and in the end combined into a
single `HLSLAttributedResourceType` instance (in
`SemaHLSL::ProcessResourceTypeAttributes`). `SemaHLSL` will also need to
short-term store the `TypeLoc` information for the new type that will be
grabbed by `TypeSpecLocFiller` soon after the type is created.
Part 1/2 of #104861
As agreed on https://github.com/itanium-cxx-abi/cxx-abi/issues/109 these
placeholders should be mangled as a `template-prefix` production.
```
<template-prefix> ::= <template unqualified-name> # global template
::= <prefix> <template unqualified-name> # nested template
::= <template-param> # template template parameter
::= <substitution>
```
Previous to this patch, the template template parameter case was not
handled, and template template parameters were incorrectly being handled
as unqualified-names.
Before #95202, DeducedTemplateType was not canonicalized correctly, so
that template template parameter declarations were retained
uncanonicalized.
After #95202, they are correctly canonicalized, but this now leads to
these TTPs being anonymous entities, where the mangling implementation
correctly doesn't expect an anonymous declaration of this kind, leading
to a crash.
Fixes#106182.
Enabling __ptr32 keyword to support in Clang for z/OS. It is represented
by addrspace(1) in LLVM IR. Unlike existing implementation, __ptr32 is
not mangled into symbol names for z/OS.
HLSL has a set of intangible types which are described in in the
[draft HLSL Specification
(**[Basic.types]**)](https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf):
There are special implementation-defined types such as handle types,
which fall into a category of standard intangible types. Intangible
types are types that have no defined object representation or value
representation, as such the size is unknown at compile time.
A class type T is an intangible class type if it contains an base
classes or members of intangible class type, standard intangible type,
or arrays of such types. Standard intangible types and intangible class
types are collectively called intangible
types([9](https://microsoft.github.io/hlsl-specs/specs/hlsl.html#Intangible)).
This PR implements one standard intangible type `__hlsl_resource_t`
and sets up the infrastructure that will make it easier to add more
in the future, such as samplers or raytracing payload handles. The
HLSL intangible types are declared in
`clang/include/clang/Basic/HLSLIntangibleTypes.def` and this file is
included with related macro definition in most places that require edits
when a new type is added.
The new types are added as keywords and not typedefs to make sure they
cannot be redeclared, and they can only be declared in builtin implicit
headers. The `__hlsl_resource_t` type represents a handle to a memory
resource and it is going to be used in builtin HLSL buffer types like this:
template <typename T>
class RWBuffer {
[[hlsl::contained_type(T)]]
[[hlsl::is_rov(false)]]
[[hlsl::resource_class(uav)]]
__hlsl_resource_t Handle;
};
Part 1/3 of llvm/llvm-project#90631.
---------
Co-authored-by: Justin Bogner <mail@justinbogner.com>
The builtin computes the discriminator for a type, which can be used to
sign/authenticate function pointers and member function pointers.
If the type passed to the builtin is a C++ member function pointer type,
the result is the discriminator used to signed member function pointers
of that type. If the type is a function, function pointer, or function
reference type, the result is the discriminator used to sign functions
of that type. It is ill-formed to use this builtin with any other type.
A call to this function is an integer constant expression.
Co-Authored-By: John McCall rjmccall@apple.com
Currently, `NamespaceDecl` has a member `AnonOrFirstNamespaceAndFlags`
which stores a few pieces of data:
- a bit indicating whether the namespace was declared `inline`, and
- a bit indicating whether the namespace was declared as a
_nested-namespace-definition_, and
- a pointer a `NamespaceDecl` that either stores:
- a pointer to the first declaration of that namespace if the
declaration is no the first declaration, or
- a pointer to the unnamed namespace that inhabits the namespace
otherwise.
`Redeclarable` already stores a pointer to the first declaration of an
entity, so it's unnecessary to store this in `NamespaceDecl`.
`DeclContext` has 8 bytes in which various bitfields can be stored for a
declaration, so it's not necessary to store these in `NamespaceDecl`
either. We only need to store a pointer to the unnamed namespace that
inhabits the first declaration of a namespace. This patch moves the two
bits currently stored in `NamespaceDecl` to `DeclContext`, and only
stores a pointer to the unnamed namespace that inhabits a namespace in
the first declaration of that namespace. Since `getOriginalNamespace`
always returns the same `NamespaceDecl` as `getFirstDecl`, this function
is removed to avoid confusion.
This reverts commit ce4aada6e2135e29839f672a6599db628b53295d and a
follow-up patch 8ef26f1289bf069ccc0d6383f2f4c0116a1206c1.
This new warning can not be fully suppressed by the
`-Wno-missing-dependent-template-keyword` flag, this gives developer no
time to do the cleanup in a large codebase, see https://github.com/llvm/llvm-project/pull/98547#issuecomment-2228250884
Reapplies #92957, fixing an instance where the `template` keyword was
missing prior to a dependent name in `llvm/ADT/ArrayRef.h`. An
_alias-declaration_ is used to work around a bug affecting GCC releases
before 11.1 (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94799) which
rejects the use of the `template` keyword prior to the
_nested-name-specifier_ in the class member access.
CWG1835 was one of the many core issues resolved by P1787R6: "Declarations and where to
find them" (http://wg21.link/p1787r6). Its resolution changes how
member-qualified names (as defined by [basic.lookup.qual.general] p2) are looked
up. This patch implementation that resolution.
Previously, an _identifier_ following `.` or `->` would be first looked
up in the type of the object expression (i.e. qualified lookup), and
then in the context of the _postfix-expression_ (i.e. unqualified
lookup) if nothing was found; the result of the second lookup was
required to name a class template. Notably, this second lookup would
occur even when the object expression was dependent, and its result
would be used to determine whether a `<` token is the start of a
_template-argument_list_.
The new wording in [basic.lookup.qual.general] p2 states:
> A member-qualified name is the (unique) component name, if any, of
> - an _unqualified-id_ or
> - a _nested-name-specifier_ of the form _`type-name ::`_ or
_`namespace-name ::`_
>
> in the id-expression of a class member access expression. A
***qualified name*** is
> - a member-qualified name or
> - the terminal name of
> - a _qualified-id_,
> - a _using-declarator_,
> - a _typename-specifier_,
> - a _qualified-namespace-specifier_, or
> - a _nested-name-specifier_, _elaborated-type-specifier_, or
_class-or-decltype_ that has a _nested-name-specifier_.
>
> The _lookup context_ of a member-qualified name is the type of its
associated object expression (considered dependent if the object
expression is type-dependent). The lookup context of any other qualified
name is the type, template, or namespace nominated by the preceding
_nested-name-specifier_.
And [basic.lookup.qual.general] p3 now states:
> _Qualified name lookup_ in a class, namespace, or enumeration performs
a search of the scope associated with it except as specified below.
Unless otherwise specified, a qualified name undergoes qualified name
lookup in its lookup context from the point where it appears unless the
lookup context either is dependent and is not the current instantiation
or is not a class or class template. If nothing is found by qualified
lookup for a member-qualified name that is the terminal name of a
_nested-name-specifier_ and is not dependent, it undergoes unqualified
lookup.
In non-standardese terms, these two paragraphs essentially state the
following:
- A name that immediately follows `.` or `->` in a class member access
expression is a member-qualified name
- A member-qualified name will be first looked up in the type of the
object expression `T` unless `T` is a dependent type that is _not_ the
current instantiation, e.g.
```
template<typename T>
struct A
{
void f(T* t)
{
this->x; // type of the object expression is 'A<T>'. although 'A<T>' is dependent, it is the
// current instantiation so we look up 'x' in the template definition context.
t->y; // type of the object expression is 'T' ('->' is transformed to '.' per [expr.ref]).
// 'T' is dependent and is *not* the current instantiation, so we lookup 'y' in the
// template instantiation context.
}
};
```
- If the first lookup finds nothing and:
- the member-qualified name is the first component of a
_nested-name-specifier_ (which could be an _identifier_ or a
_simple-template-id_), and either:
- the type of the object expression is the current instantiation and it
has no dependent base classes, or
- the type of the object expression is not dependent
then we lookup the name again, this time via unqualified lookup.
Although the second (unqualified) lookup is stated not to occur when the
member-qualified name is dependent, a dependent name will _not_ be
dependent once the template is instantiated, so the second lookup must
"occur" during instantiation if qualified lookup does not find anything.
This means that we must perform the second (unqualified) lookup during
parsing even when the type of the object expression is dependent, but
those results are _not_ used to determine whether a `<` token is the
start of a _template-argument_list_; they are stored so we can replicate
the second lookup during instantiation.
In even simpler terms (paraphrasing the meeting minutes from the review of P1787; see https://wiki.edg.com/bin/view/Wg21summer2020/P1787%28Lookup%29Review2020-06-15Through2020-06-18):
- Unqualified lookup always happens for the first name in a
_nested-name-specifier_ that follows `.` or `->`
- The result of that lookup is only used to determine whether `<` is the
start of a _template-argument-list_ if the first (qualified) lookup
found nothing and the lookup context:
- is not dependent, or
- is the current instantiation and has no dependent base classes.
An example:
```
struct A
{
void f();
};
template<typename T>
using B = A;
template<typename T>
struct C : A
{
template<typename U>
void g();
void h(T* t)
{
this->g<int>(); // ok, '<' is the start of a template-argument-list ('g' was found via qualified lookup in the current instantiation)
this->B<void>::f(); // ok, '<' is the start of a template-argument-list (current instantiation has no dependent bases, 'B' was found via unqualified lookup)
t->g<int>(); // error: '<' means less than (unqualified lookup does not occur for a member-qualified name that isn't the first component of a nested-name-specifier)
t->B<void>::f(); // error: '<' means less than (unqualified lookup does not occur if the name is dependent)
t->template B<void>::f(); // ok: '<' is the start of a template-argument-list ('template' keyword used)
}
};
```
Some additional notes:
- Per [basic.lookup.qual.general] p1, lookup for a
member-qualified name only considers namespaces, types, and templates
whose specializations are types if it's an _identifier_ followed by
`::`; lookup for the component name of a _simple-template-id_ followed
by `::` is _not_ subject to this rule.
- The wording which specifies when the second unqualified lookup occurs
appears to be paradoxical. We are supposed to do it only for the first
component name of a _nested-name-specifier_ that follows `.` or `->`
when qualified lookup finds nothing. However, when that name is followed
by `<` (potentially starting a _simple-template-id_) we don't _know_
whether it will be the start of a _nested-name-specifier_ until we do
the lookup -- but we aren't supposed to do the lookup until we know it's
part of a _nested-name-specifier_! ***However***, since we only do the
second lookup when the first lookup finds nothing (and the name isn't
dependent), ***and*** since neither lookup is type-only, the only valid
option is for the name to be the _template-name_ in a
_simple-template-id_ that is followed by `::` (it can't be an
_unqualified-id_ naming a member because we already determined that the
lookup context doesn't have a member with that name). Thus, we can lock
into the _nested-name-specifier_ interpretation and do the second lookup
without having to know whether the _simple-template-id_ will be followed
by `::` yet.
Virtual function pointer entries in v-tables are signed with address
discrimination in addition to declaration-based discrimination, where an
integer discriminator the string hash (see
`ptrauth_string_discriminator`) of the mangled name of the overridden
method. This notably provides diversity based on the full signature of
the overridden method, including the method name and parameter types.
This patch introduces ItaniumVTableContext logic to find the original
declaration of the overridden method.
On AArch64, these pointers are signed using the `IA` key (the
process-independent code key.)
V-table pointers can be signed with either no discrimination, or a
similar scheme using address and decl-based discrimination. In this
case, the integer discriminator is the string hash of the mangled
v-table identifier of the class that originally introduced the vtable
pointer.
On AArch64, these pointers are signed using the `DA` key (the
process-independent data key.)
Not using discrimination allows attackers to simply copy valid v-table
pointers from one object to another. However, using a uniform
discriminator of 0 does have positive performance and code-size
implications on AArch64, and diversity for the most important v-table
access pattern (virtual dispatch) is already better assured by the
signing schemas used on the virtual functions. It is also known that
some code in practice copies objects containing v-tables with `memcpy`,
and while this is not permitted formally, it is something that may be
invasive to eliminate.
This is controlled by:
```
-fptrauth-vtable-pointer-type-discrimination
-fptrauth-vtable-pointer-address-discrimination
```
In addition, this provides fine-grained controls in the
ptrauth_vtable_pointer attribute, which allows overriding the default
ptrauth schema for vtable pointers on a given class hierarchy, e.g.:
```
[[clang::ptrauth_vtable_pointer(no_authentication, no_address_discrimination,
no_extra_discrimination)]]
[[clang::ptrauth_vtable_pointer(default_key, default_address_discrimination,
custom_discrimination, 0xf00d)]]
```
The override is then mangled as a parametrized vendor extension:
```
"__vtptrauth" I
<key>
<addressDiscriminated>
<extraDiscriminator>
E
```
To support this attribute, this patch adds a small extension to the
attribute-emitter tablegen backend.
Note that there are known areas where signing is either missing
altogether or can be strengthened. Some will be addressed in later
changes (e.g., member function pointers, some RTTI).
`dynamic_cast` in particular is handled by emitting an artificial
v-table pointer load (in a way that always authenticates it) before the
runtime call itself, as the runtime doesn't have enough information
today to properly authenticate it. Instead, the runtime is currently
expected to strip the v-table pointer.
---------
Co-authored-by: John McCall <rjmccall@apple.com>
Co-authored-by: Ahmed Bougacha <ahmed@bougacha.org>