/*
* Copyright (c) 2000-2022 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef __CONSTRAINED_CTYPES__
#define __CONSTRAINED_CTYPES__
#include <sys/cdefs.h>
/*
* Constraining pointer types based on contracts.
*
* 1. List of supported constrained pointers.
*
* 1.1. `Reference' pointers.
*
* The `reference' pointers point to a single entity. The pointer
* arithmetics are not supported for the `reference' pointers.
*
* The `reference' pointers are fully ABI compatible with
* the unconstrained C pointers.
*
* The naming convention for the `reference' pointers uses
* the `ref' constraint tag. See `Naming conventions' below for furhter
* discussion.
*
* Examples:
*
* (1) `socket_ref_t' is `reference' pointer to `struct socket'.
* (2) `uint32_ref_t' is `reference' pointer to `uint32_t'.
*
*
* 1.2. `Checked' pointers.
*
* The `checked' pointers represent contigous data arrays, which
* can be traversed only in the direction of increasing memory addresses.
* The pointer arithmetics are partially supported: decrements (p--, --p)
* are disallowed.
*
* The `checked' pointers are not ABI-compatible with plain C pointers,
* due to the boundary checks instrumentation. See `ABI
* Compatibility Considerations' below for further discussion.
*
* The naming convention for the `checked' pointers uses the `ptr'
* constraint tag. See `Naming conventions' below for furhter discussion.
*
* Examples:
*
* (1) `socket_ptr_t' is `checked' pointer to `struct socket'.
* (2) `uint32_ptr_t' is `checked' pointer to `uint32_t'.
*
*
* 1.3. `Bidirectional' pointers.
*
* The `bidirectional' pointers represent contigous data arrays,
* which can be traversed in both directions. The pointer arithmetics are
* fully supported for the `array' pointers.
*
* The `bidirectional' pointers are not ABI-compatible with plain C
* pointers, due to the boundary checks instrumentation. Additionally,
* passing `bidirectional' pointers to functions require the use of stack.
* See `ABI Compatibility Considerations' below for further discussion.
*
* The naming convention for the `bidirectional' pointers uses
* the `bptr' constraint tag. See `Naming conventions' below for furhter
* discussion.
*
* Examples:
*
* (1) `socket_bptr_t' is `bidirectional' pointer to `struct socket'.
* (2) `uint32_bptr_t' is `bidirectional' pointer to `uint32_t'.
*
*
* 1.4. Multidimensional constrained pointers.
*
* Constraining multidimensional pointers is achieved by iteratively
* applying the constraints from the innermost type to the outermost type.
*
* Pointer arithmetics are supported for the dimensions that
* are not constrained to a `reference' or `const reference'.
*
* If any of the dimension constraints isn't ABI-compatible with its
* unconstrained counterpart, then the entire constrained multidimensional
* pointer is not ABI-compatible with the corresponding unconstrained
* multidimensional pointer. Otherwise, the two are ABI-compatible. See
* `ABI compatibility' below for further discussion.
*
* The naming convention for the multidimensional constrained pointers
* combines the naming tags that correspond to the individual constraints.
* See `Naming conventions' below for furhter discussion.
*
* Examples:
*
* (1) `socket_ref_bptr_t' is a `bidirectional' pointer to a `reference'
* pointer to `struct socket'.
* (2) `socket_ptr_ref_t' is a `reference' pointer to a `checked'
* pointer to `struct socket'.
*
*
* 1.5. Using `const', `volatile', and `restrict' type qualifiers with
* constrained types.
*
* The use of the `const', `volatile', and `restrict' type qualifiers
* (a.k.a. "CRV qualifiers") follows the syntax of the C language.
*
* As a special case, if a `const' qualifier is applied to inner
* dimensions of a multidimensional constrained pointer type, the
* constraint tag is prepended with letter `c'; thus `cref' can be used
* for const-qualified `reference' pointer. This abbreviation is only
* supported for the `const' qualifier, as use of `volatile' or `restrict'
* for inner constrained types is quite uncommon. See `Multidimensional
* constrained pointers' above and `Naming conventions' below for further
* discussion.
*
* Examples:
*
* (1) `socket_ref_t const' is the const-qualified `reference' pointer
* to `struct socket'.
* (2) `socket_ptr_t volatile' is the volatile-qualified `checked' pointer
* to `struct socket'.
* (3) `socket_ptr_ref_t const' is a const-qualified `reference' pointer
* to a `checked' pointer to `struct socket'.
* (4) `socket_cref_ptr_t const' is a `checked' pointer to a
* const-qualified `reference' pointer to `struct socket'.
*
*
* 1.6. Combining constrained pointers and unconstrained pointers.
*
* Unconstrained pointers to constrained pointers follow
* the standard C syntax. Defining constrained pointers to
* unconstrained pointers is possible via defining a constrained pointer
* to a typedef.
*
* Examples:
*
* (1) `socket_ref_t *' is an unconstrained pointer to `socket_ref_t', i.e.
* unconstrained pointer to a `reference' pointer to `struct socket'.
* (2) `socket_ref_t const *' is an unconstrained pointer to `socket_ref_t const',
* i.e. an unconstrained pointer to a const-qualified `reference'
* pointer to `struct socket'.
* (3) `socket_ref_t * const' is a const-qualified unconstrained pointer to
* `socket_ref_t', i.e. a const-qualified unconstrained pointer to a
* `reference' pointer to `struct socket'.
* (4) `intptr_ref_t' is a `reference' pointer to `intptr_t', i.e.
* a `reference' pointer to an unconstrained pointer to `int'. Note
* the use of `intptr_t' typedef, which is necessary at the moment.
*
*
* 2. Defining constrained pointer types.
*
* 2.1. Declaring multiple constrained types simultaneously.
*
* `__CCT_DECLARE_CONSTRAINED_PTR_TYPES(basetype, basetag)`
* is the suggested way to declare constrained pointer types.
*
* Parameters:
*
* `basetype`: the pointee type, including `struct' or `enum' keywords.
* `basetag`: the prefix of the constrained type.
*
* This macro acts differently in the user-space and the kernel-space
* code.
* When used in the user-space code, the macro will declare
* types which are ABI-safe. See `ABI Compatibility Considerations'
* below for more details on ABI-safety. In the user-space code,
* the macro is guarded by the `__CCT_ENABLE_USER_SPACE' compilation
* flag.
* When used in the kernel-space code, the macro will declare
* the common constrained types.
*
* Examples:
*
* (1) When used from the user space, and `__CCT_ENABLE_USER_SPACE'
* is defined, the expression
* `__CCT_DECLARE_CONSTRAINED_PTR_TYPES(struct socket, socket);'
* will declare types:
*
* (a) `socket_ref_t': the `reference' to `struct socket'
* (b) `socket_ref_ref_t': the `reference to reference'
* to `struct socket'.
*
* (2) When used from the kernel space,
* `__CCT_DECLARE_CONSTRAINED_PTR_TYPES(struct socket, socket);'
* will declare the above types, plus:
*
* (c) `socket_ptr_t': `checked' pointer to `struct socket'.
* (d) `socket_bptr_t': `bidirectional' pointer to `struct socket'.
* (e) `socket_ref_ptr_t': `checked' pointer to a `reference'
* to `struct socket'.
* (f) `socket_ptr_ref_t': `reference' to a `checked' pointer
* to `struct socket'.
*
* These additional types are not ABI-safe, and therefore are not exposed
* to the user space. See `ABI Compatibility Considerations' below.
*
*
* 2.2. Declaring individual constrained types.
*
* The above macro attempts to do many things at once, and under some
* circumstances can be not appropriate. For these circumstances, a
* finer-graned declarator can be used:
*
* `__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, ...)'
*
* Parameters:
*
* `basetype`: the pointee type.
* `basetag`: the prefix of the constrained type.
* `...`: list of constraints:
* - `__CCT_REF' for the "reference" contract;
* - `__CCT_CREF' for the "const reference" contract;
* - `__CCT_PTR' for the "checked pointer" contract; or
* - `__CCT_BPTR' for the "bidirectional pointer" contract.
*
* Examples:
*
* (1) `__CCT_DECLARE_CONSTRAINED_PTR_TYPE(struct socket, socket, __CCT_REF)'
* will declare the type
* `reference' pointer to `struct socket'
* and call this type by `socket_ref_t'
*
* (2) `__CCT_DECLARE_CONSTRAINED_PTR_TYPE(struct socket, socket, __CCT_REF, __CCT_PTR)'
* will declare the type
* `checked' pointer to `socket_ref_t'
* which in turn is equivalent to the type
* `checked' pointer to `reference' pointer to `struct socket'
*
* (3) `__CCT_DECLARE_CONSTRAINED_PTR_TYPE(struct socket, socket, __CCT_REF, __CCT_PTR, __CCT_REF)'
* will declare the type
* `reference' pointer to `socket_ref_ptr_t'
* which is equivalent to the type
* `reference' pointer to `checked' pointer to `socket_ref_t'
* which in turn is equivalent to the type
* `reference' pointer to `checked' pointer to `reference' pointer to `struct socket'
*
*
* 3. Using constrained pointer types.
*
* 3.1. Using constrained pointers for local variables.
*
* Constraining the pointers on the stack reduces the risk of stack
* overflow. Therefore, it is highly suggested to use the constrained
* versions of the pointers for stack parameters. For local array
* variables, opt for the `bidirectional' pointers. If only a single value
* needs to be pointed, opt for the `reference' pointers.
*
* There are two alternative approaches for using the `reference' pointers.
* One approach is to explicitly use `thing_ref_t ptr` instead of `thing *ptr`.
* The other approach is to surround the code with the directives
* `__ASSUME_PTR_ABI_SINGLE_BEGIN' and `__ASSUME_PTR_ABI_SINGLE_END', which
* will have the effect of turning every unconstrained pointer to its
* `reference' counterpart.
*
*
* 3.2. Using constrained pointers for function parameters
*
* 3.2.1. Use `reference' pointers for scalar parameters.
*
* Scalar parameters are safe to use across ABI boundaries.
*
* Examples:
*
* (1) Using `reference' pointers for scalar input:
*
* errno_t thing_is_valid(const thing_ref_t t)
* {
* return t == NULL ? EINVAL : 0;
* }
*
*
* (2) Using `reference' pointers for scalar output, which is
* allocated by the caller:
*
* errno_t thing_copy(const thing_ref_t src, thing_ref_t dst)
* {
* if (src == NULL || dst == NULL) {
* return EINVAL;
* }
* bcopy(src, dst);
* return 0;
* }
*
* (3) Using `reference to reference' for scalar output that is
* allocated by the callee:
*
* errno_t thing_dup(const thing_ref_t src, thing_ref_ref_t dst)
* {
* *dst = malloc(sizeof(*dst));
* bcopy(src, *dst, sizeof(*src));
* return 0;
* }
*
*
* 3.2.2. Use `checked' pointers for vector parameters.
*
* When the ABI isn't a concern, use of `checked' pointers
* increases the code readability.
*
* See `ABI Compatibility Considerations' below for vector parameters when
* ABI is a concern.
*
* Examples:
*
* (1) Using `checked' pointers for vector input:
*
* errno_t thing_find_best(const thing_ref_ptr_t things,
* thing_ref_ref_t best, size_t count)
* {
* for (int i = 0; i < count; i++) {
* if (thing_is_the_best(things[i])) {
* *best = things[i];
* return 0;
* }
* }
* return ENOENT; // no best thing
* }
*
* (2) Using `checked' pointers for vector output parameters that
* are allocated by caller:
*
* errno_t thing_copy_things(thing_ref_ptr_t src, thing_ref_ptr_t dst,
* size_t count)
* {
* for (int i = 0; i < count; i++) {
* dst[i] = malloc(sizeof(*dst[i]));
* bcopy(src[i], dst[i], sizeof(*src[i]));
* }
* return 0;
* }
*
* (3) Using `reference to checked' pointers for vector output
* parameters that are allocated by callee:
*
* errno_t thing_dup_things(thing_ref_ptr_t src, thing_ref_ptr_ref_t dst,
* size_t count)
* {
* *dst = malloc(sizeof(**src) * count);
* return thing_copy_things(src, *dst, count);
* }
*
*
* 3.3. Using constrained pointers in struct definitions
*
* Examples:
*
* (1) Using a structure that points to array of things:
*
* struct things_crate {
* size_t tc_count;
* thing_bptr_t tc_things;
* };
*
*
* 4. ABI Compatibility Considerations
*
* The pointer instrumentation process has ABI implications.
*
* When the pointer insrumentation is enabled, the size of `bidirectional'
* and `checked' pointers exceeds the size of the machine word.
*
* Thus, if there is a concern that the instrumentation is enabled only in
* some compilation units that use the function, these constrained
* pointers can not be used for function parameters.
*
* Instead, one should rely on `__counted_by(count)' or `__sized_by(size)'
* attributes. These attributes accept as a parameter the name of a
* variable that contains the cont of items, or the byte size, of the
* pointed-to array. Use of these attributes does not change the size of
* the pointer.
*
* The tradeoff is between maintaining code readabilty and ABI compatibility.
*
* A common pattern is to split the function into the implementation,
* which is statically linked and therefore is ABI-safe, and the interface
* wrapper, which uses `__counted_by' or `__sized_by' to preserve ABI
* compatibility.
*
*
* 4.1. When ABI is a concern, replace `bidirectional' and `checked'
* with `__counted_by(count)` and `__sized_by(size)` for vector
* parameters.
*
*
* Examples:
*
* (1) Using `const thing_ref_t __counted_by(count)' instead of `const
* thing_ref_ptr_t' for vector input in a wrapper:
*
* errno_t thing_find_best_compat(const thing_ref_t __counted_by(count)things,
* thing_ref_ref_t best, size_t count)
* {
* // __counted_by implicitly upgraded to `checked'
* return thing_find_best(things, best, count);
* }
*
* (2) Using `thing_ref_t __counted_by(count)' instead of `thing_ref_ptr_t'
* for vector output in a wrapper.
*
* errno_t thing_copy_things_compat(thing_ref_t __counted_by(count)src,
* things_ref_t __counted_by(count)dst,
* size_t count)
* {
* // __counted_by implicitly upgraded to `checked'
* return thing_copy_things(src, dst, count);
* }
*
*
* 4.2. When ABI is a concern, use `__counted_by(count)' and
* `__sized_by(size)' for struct members that point to arrays.
*
* Examples:
*
* (1) Using a structure that points to array of things:
*
* struct things_crate {
* size_t tc_count;
* struct thing * __counted_by(tc_count)tc_things;
* };
*
* 5. Naming conventions
*
* If `typename' is the name of a C type, and `tag' is a constraint tag
* (one of `ref', `ptr', or `bptr'), then the name of a pointer to
* `typename' constrained by `tag' is `basetag_tag_t', where `basename'
* is defined by:
*
* (a) If `typename' is a name of an integral type, then `basetag' is same
* as `typename'.
* (b) If `typename' is a name of a function type, then `basetag' is same
* as `typename'.
* (c) If `typename' is a name of a structure, then `basetag' is formed by
* stripping the `struct' keyword from `typename'.
* (d) If `typename' is a name of an enumeration, then `basetag' is formed
* by stripping the `enum' keyword from `typename'.
* (e) If `typename' is a name of a typedef to a struct or an enum that ends
* with `_t', then `basetag' is formed by stripping the `_t' suffix
* from `typename'. See (h) below for when `typename' is a pointer typedef.
* (f) If `typename' is a name of constrained pointer type ending with `_t',
* then `basetag' is formed by stripping the `_t' suffix from `typename'.
*
* Additionally, constrained pointers to constrained const pointers are a
* special case:
*
* (g) If `typename' is a name of a constrained pointer type, ending with
* `_{innertag}_t', and `typename' has `const' qualifier, then `basetag'
* is formed by replacing `_{innertag}_t' with `_c{innertag}'
*
* Finally, sometimes `name_t' represents not `struct name' but `struct name *'.
* This creates additional special case:
*
* (h) If `typename' is a pointer typedef named `{struct}_t`, such as
* `mbuf_t', then creating a constrained pointer to a `typename' would
* require creating a constrained pointer to an unconstrained pointer,
* which is not supported at the moment. Instead, a constrained pointer to
* `typeof(*typename)` must be created first, and constrained again. Using
* the `mbuf_t` example, first one should create a constrained pointer to
* `struct mbuf`, e.g, `mbuf_bptr_t`, and then constrain it again with
* `tag`, leading to `mbuf_bptr_ref_t'.
*
* Examples:
*
* (1) `int_ref_t' is a `reference pointer' to `int', following the rule (a) above.
* (2) `so_pru_ref_t' is a `reference pointer' to function `so_pru',
* following the rule (b) above.
* (3) `socket_ref_t' is a `reference pointer' to `struct socket',
* following the rule (c) above.
* (4) `classq_pkt_type_ref_t' is a `reference pointer' to `enum classq_pkt_type'
* following the rule (d) above.
* (5) `classq_pkt_type_ref_t' is a also `reference pointer' to `classq_pkt_type_t'
* following the rule (e) above.
* (6) `socket_ref_ref_t' is a `reference pointer' to `socket_ref_t`,
* following the rule (f) above.
* (7) `socket_cref_ref_t' is a `reference pointer' to `socket_ref_t const`,
* following the rule (g) above.
* (8) `mbuf_ref_ref_t', is a `reference pointer' to `mbuf_ref_t`, and is one
* possible result of creating a `reference pointer' to `mbuf_t',
* following the rule (h) above.
* (9) `mbuf_bptr_ref_t', is a `reference pointer' to `mbuf_bptr_t`, and
* is another possible result of creating a `reference pointer' to
* `mbuf_t', following the rule (h) above.
*
*/
/*
* Constraint contract constants.
*
* At the moment only clang (when compiled with `ptrcheck' feature) supports
* pointer tagging via `__single', `__indexable' and `__bidi_indexable' attributes.
*
* During the transitional period, the `__indexable__' and `__bidi_indexable'
* constraints will decay to raw pointers if the `ptrcheck' feature is not enabled.
* Once the transitional period is over, the `__CCT_CONTRACT_ATTR_{B}PTR' constraints
* will stop decaying to raw pointers when built by sufficiently recent version
* of clang.
*
* Support for other compilers will be added after the introduction of support
* for pointer tagging on those compilers.
*/
#if defined(KERNEL) || defined(__CCT_ENABLE_USER_SPACE)
#if defined(__clang__)
#define __CCT_CONTRACT_ATTR___CCT_REF __single
#define __CCT_CONTRACT_ATTR___CCT_CREF const __single
#if __has_ptrcheck
#define __CCT_CONTRACT_ATTR___CCT_BPTR __bidi_indexable
#define __CCT_CONTRACT_ATTR___CCT_PTR __indexable
#else /* __clang__ + __has_ptrcheck */
#define __CCT_CONTRACT_ATTR___CCT_BPTR
#define __CCT_CONTRACT_ATTR___CCT_PTR
#endif /* __clang__ + !__has_ptrcheck */
#else /* !__clang__ */
#define __CCT_CONTRACT_ATTR___CCT_REF
#define __CCT_CONTRACT_ATTR___CCT_CREF const
#define __CCT_CONTRACT_ATTR___CCT_BPTR
#define __CCT_CONTRACT_ATTR___CCT_PTR
#endif /* __clang__ */
#define __CCT_CONTRACT_TAG___CCT_REF _ref
#define __CCT_CONTRACT_TAG___CCT_CREF _cref
#define __CCT_CONTRACT_TAG___CCT_BPTR _bptr
#define __CCT_CONTRACT_TAG___CCT_PTR _ptr
/* Helper macros */
#define __CCT_DEFER(F, ...) F(__VA_ARGS__)
#define __CCT_CONTRACT_TO_ATTR(kind) __CONCAT(__CCT_CONTRACT_ATTR_, kind)
#define __CCT_CONTRACT_TO_TAG(kind) __CCT_DEFER(__CONCAT, __CCT_CONTRACT_TAG_, kind)
#define __CCT_COUNT_ARGS1(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, N, ...) N
#define __CCT_COUNT_ARGS(...) \
__CCT_COUNT_ARGS1(, __VA_ARGS__, _9, _8, _7, _6, _5, _4, _3, _2, _1, _0)
#define __CCT_DISPATCH1(base, N, ...) __CONCAT(base, N)(__VA_ARGS__)
#define __CCT_DISPATCH(base, ...) \
__CCT_DISPATCH1(base, __CCT_COUNT_ARGS(__VA_ARGS__), __VA_ARGS__)
/* Covert a contract list to a type suffix */
#define __CCT_CONTRACT_LIST_TO_TAGGED_SUFFIX_1(kind) \
__CCT_DEFER(__CONCAT, __CCT_CONTRACT_TO_TAG(kind), _t)
#define __CCT_CONTRACT_LIST_TO_TAGGED_SUFFIX_2(kind1, kind2) \
__CCT_DEFER(__CONCAT, __CCT_CONTRACT_TO_TAG(kind1), \
__CCT_CONTRACT_LIST_TO_TAGGED_SUFFIX_1(kind2))
#define __CCT_CONTRACT_LIST_TO_TAGGED_SUFFIX_3(kind1, kind2, kind3) \
__CCT_DEFER(__CONCAT, __CCT_CONTRACT_TO_TAG(kind1), \
__CCT_CONTRACT_LIST_TO_TAGGED_SUFFIX_2(kind2, kind3))
/* Create typedefs for the constrained pointer type */
#define __CCT_DECLARE_CONSTRAINED_PTR_TYPE_3(basetype, basetag, kind) \
typedef basetype * __CCT_CONTRACT_TO_ATTR(kind) \
__CCT_DEFER(__CONCAT, basetag, __CCT_CONTRACT_LIST_TO_TAGGED_SUFFIX_1(kind))
#define __CCT_DECLARE_CONSTRAINED_PTR_TYPE_4(basetype, basetag, kind1, kind2) \
typedef basetype * __CCT_CONTRACT_TO_ATTR(kind1) \
* __CCT_CONTRACT_TO_ATTR(kind2) \
__CCT_DEFER(__CONCAT, basetag, __CCT_CONTRACT_LIST_TO_TAGGED_SUFFIX_2(kind1, kind2))
#define __CCT_DECLARE_CONSTRAINED_PTR_TYPE_5(basetype, basetag, kind1, kind2, kind3) \
typedef basetype * __CCT_CONTRACT_TO_ATTR(kind1) \
* __CCT_CONTRACT_TO_ATTR(kind2) \
* __CCT_CONTRACT_TO_ATTR(kind3) \
__CCT_DEFER(__CONCAT, basetag, __CCT_CONTRACT_LIST_TO_TAGGED_SUFFIX_3(kind1, kind2, kind3))
#endif /* defined(KERNEL) || defined(__CCT_ENABLE_USER_SPACE) */
/*
* Lower level type constructor.
*/
#if defined(KERNEL) || defined(__CCT_ENABLE_USER_SPACE)
#define __CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, ...) \
__CCT_DISPATCH(__CCT_DECLARE_CONSTRAINED_PTR_TYPE, basetype, basetag, __VA_ARGS__)
#else /* !defined(KERNEL) && !defined(__CCT_ENABLE_USER_SPACE) */
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wextra-semi"
#endif /* defined(__clang__) */
#define __CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, ...)
#if defined(__clang__)
#pragma clang diagnostic pop
#endif /* defined(__clang__) */
#endif /* !defined(KERNEL) && !defined(__CCT_ENABLE_USER_SPACE) */
/*
* Higher level type constructors.
*/
#if defined(KERNEL)
/*
* The constrained types that can potentially break the ABI are not exposed
* into the user-space.
*/
#define __CCT_DECLARE_CONSTRAINED_PTR_TYPES(basetype, basetag) \
__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, __CCT_REF); \
__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, __CCT_BPTR); \
__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, __CCT_PTR); \
__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, __CCT_REF, __CCT_REF); \
__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, __CCT_REF, __CCT_PTR); \
__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, __CCT_PTR, __CCT_REF)
#else /* !defined(KERNEL) */
#if defined(__CCT_ENABLE_USER_SPACE)
/* Limiting the higher-level constructor to the ABI-preserving constructs. */
#define __CCT_DECLARE_CONSTRAINED_PTR_TYPES(basetype, basetag) \
__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, __CCT_REF); \
__CCT_DECLARE_CONSTRAINED_PTR_TYPE(basetype, basetag, __CCT_REF, __CCT_REF)
#else /* !defined(__CCT_ENABLE_USER_SPACE) */
/* Disabling the higher-level constructor */
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wextra-semi"
#endif /* defined(__clang__) */
#define __CCT_DECLARE_CONSTRAINED_PTR_TYPES(basetype, basetag)
#if defined(__clang__)
#pragma clang diagnostic pop
#endif /* defined(__clang__) */
#endif /* !defined(__CCT_ENABLE_USER_SPACE) */
#endif /* !defined(KERNEL) */
#endif /* __CONSTRAINED_CTYPES__ */