Repository: CTSRD-CHERI/llvm-project
Pull request #763: Refine CHERI macro and feature definitions
Author: login: brooksdavis
Created: 2025-02-28T23:43:39Z | Merged: 2025-03-17T21:30:55Z

This set of changes does three main things:
 - adds an `__CHERI_HYBRID__` to indicate hybrid compilation
 - adds an `__has_feature(cheri)` to eventually replace the overly generic `__has_feature(capabilities)`
 - Makes `__CHERI__` a synonym for `__CHERI_PURE_CAPABILITY__` and adds an `__CHERI_HYBRID__` **This is a breaking change**
        
Rationale: We strongly encourage all CHERI consumers to use a pure-capability ABI whenever possible. Therefore it should be the easiest thing to type and less preferred options should be longer. The existing macros date to the earliest compiler support which barely supported capability types. Before broad adoption of CHERI we should make the macros be sensible. We're past Stuart Feldman's too many users of `make` to change the tabs threshold (12), but few codebases will be effected and the required changes are simple and can be safely performed automatically. We shouldn't have to live with this aspect of history forever.


Diff:
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 16ce88d12d010..f42404b3ed995 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -240,6 +240,7 @@ FEATURE(experimental_library, LangOpts.ExperimentalLibrary)
 
 // CHERI features:
 FEATURE(capabilities, PP.getTargetInfo().SupportsCapabilities())
+FEATURE(cheri, PP.getTargetInfo().SupportsCapabilities())
 FEATURE(pointer_interpretation, PP.getTargetInfo().SupportsCapabilities())
 FEATURE(cheri_casts, PP.getTargetInfo().SupportsCapabilities())
 
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index c57bccc46cdb7..cb83388c0e95d 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -997,7 +997,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
   if (TI.SupportsCapabilities()) {
     const uint64_t CapWidth = TI.getCHERICapabilityWidth();
     const uint64_t CapRange = TI.getPointerRangeForCHERICapability();
-    Builder.defineMacro("__CHERI__", "1"); // TODO: or define __CHERI__ to 128/256?
     Builder.defineMacro("__CHERI_CAPABILITY_WIDTH__", Twine(CapWidth));
     DefineTypeSizeof("__SIZEOF_CHERI_CAPABILITY__", CapWidth, TI, Builder);
     Builder.defineMacro("__CHERI_ADDRESS_BITS__", Twine(CapRange));
@@ -1012,6 +1011,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
     DefineTypeSize("__UINTCAP_MAX__", TI.getIntTypeByWidth(CapRange, false), TI, Builder);
 
     if (TI.areAllPointersCapabilities()) {
+      Builder.defineMacro("__CHERI__");
+
       // XXXAR is there a reason we use two instead of just defining it?
       // I don't think we have any checks that rely on the value
       Builder.defineMacro("__CHERI_PURE_CAPABILITY__", "2");
@@ -1023,6 +1024,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
       if (LangOpts.getCheriBounds() > LangOptions::CBM_Conservative)
         Builder.defineMacro("__CHERI_SUBOBJECT_BOUNDS__",
                             Twine(LangOpts.getCheriBounds()));
+    } else {
+      Builder.defineMacro("__CHERI_HYBRID__");
     }
   }
 
diff --git a/clang/test/CodeGen/builtin-align.c b/clang/test/CodeGen/builtin-align.c
index 7d38bd0723572..044b8676048d2 100644
--- a/clang/test/CodeGen/builtin-align.c
+++ b/clang/test/CodeGen/builtin-align.c
@@ -40,7 +40,7 @@
 #error MISSING TYPE
 #endif
 
-#ifndef __CHERI__
+#if !__has_feature(cheri)
 #define __capability
 #endif
 
diff --git a/clang/test/CodeGen/cheri/warn-ctoptr-functions.c b/clang/test/CodeGen/cheri/warn-ctoptr-functions.c
index 0de2d0e97efd4..490ce1f9609ea 100644
--- a/clang/test/CodeGen/cheri/warn-ctoptr-functions.c
+++ b/clang/test/CodeGen/cheri/warn-ctoptr-functions.c
@@ -22,7 +22,7 @@ typedef	__sighandler_t	* __kerncap sig_t;	/* type of pointer to a signal functio
 typedef long sigset_t;
 struct __siginfo;
 
-#if __has_feature(capabilities)
+#if __has_feature(cheri)
 struct sigaction_c {
 	union {
 		void    (* __capability __sa_handler)(int);
@@ -42,7 +42,7 @@ struct sigaction_native {
 	sigset_t sa_mask;		/* signal mask to apply */
 };
 
-#if __has_feature(capabilities)
+#if __has_feature(cheri)
 typedef struct sigaction_c	ksigaction_t;
 #else
 typedef	struct sigaction_native	ksigaction_t;
diff --git a/clang/test/CodeGenCXX/cheri/constinit-zero-to-pointer.cpp b/clang/test/CodeGenCXX/cheri/constinit-zero-to-pointer.cpp
index 994e82fe4fcc5..0f9f564684508 100644
--- a/clang/test/CodeGenCXX/cheri/constinit-zero-to-pointer.cpp
+++ b/clang/test/CodeGenCXX/cheri/constinit-zero-to-pointer.cpp
@@ -24,7 +24,7 @@ const AttributeData kBarcodeAttributeData{
 AttributeData test() { return kBarcodeAttributeData; }
 
 /// Also check enums with underlying type __intcap for CHERI targets:
-#if __has_feature(capabilities)
+#if __has_feature(cheri)
 enum class IntCapEnum : __intcap { Zero };
 
 void *intcapEnumToPtrConstant = (void *)IntCapEnum::Zero;
diff --git a/clang/test/Driver/cheri/bounds-mode.c b/clang/test/Driver/cheri/bounds-mode.c
index 1b66a0ce8fa91..5ac92acc644cb 100644
--- a/clang/test/Driver/cheri/bounds-mode.c
+++ b/clang/test/Driver/cheri/bounds-mode.c
@@ -17,3 +17,4 @@
 // CHECK: #define __CHERI_PURE_CAPABILITY__ 2
 // SUBOBJECT-DISABLED-NOT: __CHERI_SUBOBJECT_BOUNDS__
 // SUBOBJECT-SAFE: #define __CHERI_SUBOBJECT_BOUNDS__ 2
+// CHECK: #define __CHERI__ 1
diff --git a/clang/test/Preprocessor/cheri-cap-sizes.c b/clang/test/Preprocessor/cheri-cap-sizes.c
index 2bf52173fb9ed..9436599ea00c3 100644
--- a/clang/test/Preprocessor/cheri-cap-sizes.c
+++ b/clang/test/Preprocessor/cheri-cap-sizes.c
@@ -37,8 +37,10 @@
 // CHECK: #define __CHERI_ADDRESS_BITS__ 64
 // CHERI128: #define __CHERI_CAPABILITY_WIDTH__ 128
 // PURECAP: #define __CHERI_PURE_CAPABILITY__ 2
+// PURECAP: #define __CHERI__ 1
 // MIPS-NOT: __CHERI_PURE_CAPABILITY__
-// CHECK: #define __CHERI__ 1
+// MIPS-NOT: __CHERI__
+// MIPS: #define __CHERI_HYBRID__ 1
 // Note: 64-bit range for intcap makes more sense than the full range for pointers
 // CHECK: #define __INTCAP_MAX__ 9223372036854775807L
 
diff --git a/clang/test/Preprocessor/cheri-features.c b/clang/test/Preprocessor/cheri-features.c
index 10365e3d964f6..2d10f87f59ae1 100644
--- a/clang/test/Preprocessor/cheri-features.c
+++ b/clang/test/Preprocessor/cheri-features.c
@@ -5,6 +5,15 @@
 // RUN:   2>&1 | FileCheck --check-prefix=CHECK-MIPS %s
 
 
+#if __has_feature(cheri)
+#pragma message("__has_feature(cheri)")
+// CHECK-CHERI: warning: __has_feature(cheri)
+void* __capability w = 0;
+#else
+#pragma message("no cheri")
+// CHECK-MIPS: warning: no cheri
+#endif
+
 #if __has_feature(capabilities)
 #pragma message("__has_feature(capabilities)")
 // CHECK-CHERI: warning: __has_feature(capabilities)
@@ -16,13 +25,22 @@ void* __capability x = 0;
 
 #if defined(__CHERI__)
 #pragma message("__CHERI__ defined")
-// CHECK-CHERI: warning: __CHERI__ defined
 void* __capability y = 0;
 #else
 #pragma message("__CHERI__ not defined")
+// CHECK-CHERI: warning: __CHERI__ not defined
 // CHECK-MIPS: warning: __CHERI__ not defined
 #endif
 
+#if defined(__CHERI_HYBRID__)
+#pragma message("__CHERI_HYBRID__ defined")
+// CHECK-CHERI: warning: __CHERI_HYBRID__ defined
+void* __capability y = 0;
+#else
+#pragma message("__CHERI_HYBRID__ not defined")
+// CHECK-MIPS: warning: __CHERI_HYBRID__ not defined
+#endif
+
 int main() {
 	return 0;
 }
diff --git a/clang/test/Preprocessor/cheri-riscv-feature-flags.c b/clang/test/Preprocessor/cheri-riscv-feature-flags.c
index 886ede81e78f2..9e73265ddad97 100644
--- a/clang/test/Preprocessor/cheri-riscv-feature-flags.c
+++ b/clang/test/Preprocessor/cheri-riscv-feature-flags.c
@@ -18,7 +18,7 @@
 // CHECK: #define __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ 64
 // CHECK: #define __CHERI_CAP_PERMISSION_PERMIT_STORE__ 8
 // CHECK: #define __CHERI_CAP_PERMISSION_PERMIT_UNSEAL__ 512
-// CHECK: #define __CHERI__ 1
+// CHECK: #define __CHERI_HYBRID__ 1
 // CHECK32: #define __SIZEOF_CHERI_CAPABILITY__ 8
 // CHECK64: #define __SIZEOF_CHERI_CAPABILITY__ 16
 // __VERSION__ and __clang_version__ could contain CHERI due to the Git URL.
diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c
index 27e76391b80b7..7fb182f1be28d 100644
--- a/clang/test/Preprocessor/init.c
+++ b/clang/test/Preprocessor/init.c
@@ -355,7 +355,7 @@
 // CHERI-COMMON-NEXT: #define __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ 64
 // CHERI-COMMON-NEXT: #define __CHERI_CAP_PERMISSION_PERMIT_STORE__ 8
 // CHERI-COMMON-NEXT: #define __CHERI_CAP_PERMISSION_PERMIT_UNSEAL__ 512
-// CHERI-COMMON-NEXT: #define __CHERI__ 1
+// CHERI-COMMON-NEXT: #define __CHERI_HYBRID__ 1
 // CHERI64:           #define __POINTER_WIDTH__ 32
 // CHERI128:          #define __POINTER_WIDTH__ 64
 // CHERI-COMMON-NEXT: #define __PRAGMA_REDEFINE_EXTNAME 1
@@ -407,6 +407,7 @@
 // CHERI128-PURECAP: #define _MIPS_FPSET 32
 // CHERI128-PURECAP: #define __CHERI_PURE_CAPABILITY__ 2
 // CHERI128-PURECAP: #define __CHERI_SANDBOX__ 4
+// CHERI128-PURECAP: #define __CHERI__ 1
 // CHERI128-PURECAP: #define __INTPTR_FMTd__ "Pd"
 // CHERI128-PURECAP: #define __INTPTR_FMTi__ "Pi"
 // CHERI128-PURECAP: #define __INTPTR_MAX__ 9223372036854775807L
diff --git a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp
index d50f71aa3d8a1..a7d31fe6de3ad 100644
--- a/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp
+++ b/clang/test/SemaCXX/cheri/cheri-pointer-cast.cpp
@@ -9,7 +9,7 @@ typedef unsigned long ulong;
 
 int foo;
 
-#ifdef __CHERI__
+#if __has_feature(cheri)
 #define CAP __capability
 #else
 #define CAP
@@ -68,7 +68,7 @@ int main() {
 }
 
 // Check that we don't warn on dependent types
-#ifdef __CHERI__
+#if __has_feature(cheri)
 template <typename T>
 long offset_get(T x) {
   return __builtin_cheri_offset_get(reinterpret_cast<void * __capability>(x));
diff --git a/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp b/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp
index 0cb11821bed95..39103f1c31ad8 100644
--- a/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp
+++ b/clang/test/SemaCXX/cheri/dependent-cast-crash.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only %s -verify
 // RUN: %cheri_cc1 -fsyntax-only %s -verify
 // RUN: %cheri_purecap_cc1 -fsyntax-only %s -verify
-#if !__has_feature(capabilities)
+#if !__has_feature(cheri)
 #define __capability
 #endif
 
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 5e21df86b528b..0ac9add6c5f58 100644
--- a/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp
+++ b/clang/test/SemaCXX/cheri/implicit-cap-conversion-return-value.cpp
@@ -7,7 +7,7 @@
 // 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
 
-#if __has_feature(capabilities)
+#if __has_feature(cheri)
 typedef unsigned __intcap uintcap_t;
 #else
 typedef unsigned long uintcap_t;
diff --git a/clang/test/SemaCXX/cheri/overloaded-function-template-arg.cpp b/clang/test/SemaCXX/cheri/overloaded-function-template-arg.cpp
index 9b1bf25433641..dbec6059d527b 100644
--- a/clang/test/SemaCXX/cheri/overloaded-function-template-arg.cpp
+++ b/clang/test/SemaCXX/cheri/overloaded-function-template-arg.cpp
@@ -32,7 +32,7 @@ void instantiate() {
   c<void(char), a>::function(1);         // expected-error{{address of overloaded function 'a' does not match required type 'void (char)'}}
 }
 
-#if __has_feature(capabilities)
+#if __has_feature(cheri)
 template <class T, T *__capability Func>
 // hybrid-note@-1 3 {{template parameter is declared here}}
 struct c_cap {
diff --git a/libcxx/include/limits b/libcxx/include/limits
index a0705145ae425..ee0f4ce4e789f 100644
--- a/libcxx/include/limits
+++ b/libcxx/include/limits
@@ -447,7 +447,7 @@ protected:
     static _LIBCPP_CONSTEXPR const float_round_style round_style = round_to_nearest;
 };
 
-#ifdef __CHERI__
+#if __has_feature(capabilities)
 template<>
 class __libcpp_numeric_limits<__intcap_t, true>
   : public __libcpp_numeric_limits<long, true> { };
diff --git a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
index 67449a84ed166..e75aa7403ac99 100644
--- a/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
@@ -115,9 +115,9 @@ int main(int, char**)
     test<__uint128_t>();
 #endif
 
-#if defined(__CHERI__) && !defined(__CHERI_PURE_CAPABILITY__)
-  test<__intcap_t>();
-  test<__uintcap_t>();
+#ifdef __CHERI_HYBRID__
+    test<__intcap_t>();
+    test<__uintcap_t>();
 #endif
 
   return 0;
diff --git a/libcxx/test/support/charconv_test_helpers.h b/libcxx/test/support/charconv_test_helpers.h
index efdaeb82bb65c..f27f9a7fdf627 100644
--- a/libcxx/test/support/charconv_test_helpers.h
+++ b/libcxx/test/support/charconv_test_helpers.h
@@ -303,7 +303,7 @@ auto all_signed = type_list<
     ,
     __int128_t
 #endif
-#if __has_feature(capabilities)
+#if __has_feature(cheri)
     , __intcap
 #endif
     >();
@@ -317,7 +317,7 @@ auto all_unsigned = type_list<
     ,
     __uint128_t
 #endif
-#if __has_feature(capabilities)
+#if __has_feature(cheri)
     , unsigned __intcap
 #endif
     >();
diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp
index 55096ec40247c..4ae173a4ffeae 100644
--- a/libunwind/src/AddressSpace.hpp
+++ b/libunwind/src/AddressSpace.hpp
@@ -174,7 +174,7 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace {
 public:
   typedef uintptr_t pint_t;
   typedef intptr_t  sint_t;
-#ifndef __CHERI__
+#if !__has_feature(capabilities)
   typedef libunwind::fake_capability_t capability_t;
 #else
   typedef ::uintcap_t capability_t;
@@ -342,7 +342,7 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace {
   static pint_t to_pint_t(capability_t cap) {
 #ifdef __CHERI_PURE_CAPABILITY__
     return (uintcap_t)cap;
-#elif defined(__CHERI__)
+#elif __has_feature(capabilities)
     return (__cheri_addr pint_t)cap;
 #else
     pint_t result;
@@ -351,7 +351,7 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace {
 #endif
   }
   static capability_t to_capability_t(pint_t pint) {
-#ifdef __CHERI__
+#if __has_feature(capabilities)
     return (uintcap_t)pint;
 #else
     capability_t result;
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index 5a5ac95da26cd..7793b6d6ca2d6 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -460,7 +460,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
 // XXXAR: I am not entirely sure these operations should work on a uintcap_t
 // but if it's an untagged integer value it is fine
 #pragma clang diagnostic push
-#ifdef __CHERI__
+#if __has_feature(capabilities)
 #pragma clang diagnostic ignored "-Wcheri-bitwise-operations"
 #endif
   const bool log = true;
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index af090fad643bb..034e00c388d2c 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -24,7 +24,7 @@ namespace libunwind {
 // For emulating 128-bit registers
 struct v128 { uint32_t vec[4]; };
 // For emulating CHERI capability
-#ifndef __CHERI__
+#if !_has_feature(capabilities)
 struct __attribute__((aligned(16))) fake_capability {
   char bytes[16];
 };
@@ -3291,7 +3291,7 @@ class _LIBUNWIND_HIDDEN Registers_mips_newabi {
   Registers_mips_newabi();
   Registers_mips_newabi(const void *registers);
   CAPABILITIES_NOT_SUPPORTED
-#ifdef __CHERI__
+#if __has_feature(capabilities)
 #pragma message("Should also handle capability registers here.")
 #endif
 


Reviews:
user: login: arichardson
body: Technically this is a major breaking change but I don't think there is much choice outside of cheribsd that uses it so LGTM if @jrtc27 is also happy with it
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-03T17:17:30Z
user: login: arichardson
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-04T19:08:54Z
user: login: arichardson
body: Thanks for the new change, LGTM. Will wait for @jrtc27 for merging though
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-04T19:09:38Z
user: login: jrtc27
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-14T19:59:33Z
user: login: jrtc27
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-14T20:00:23Z
user: login: jrtc27
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-14T20:03:19Z
user: login: jrtc27
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-14T21:48:13Z
user: login: brooksdavis
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-14T22:01:43Z
user: login: arichardson
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-14T23:32:48Z

Review comments:
diff_hunk: @@ -25,7 +25,7 @@ void* __capability x = 0;
 
 #if defined(__CHERI__)
path: clang/test/Preprocessor/cheri-features.c
user: login: arichardson
body: Could we add a test for the new hybrid macro here? And maybe update the RUN lines for RISC-V instead of MIPS? But that can be done in a future commit
created_at: 2025-03-04T19:08:54Z
author_association: MEMBER
diff_hunk: @@ -1012,6 +1011,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
     DefineTypeSize("__UINTCAP_MAX__", TI.getIntTypeByWidth(CapRange, false), TI, Builder);
 
     if (TI.areAllPointersCapabilities()) {
+      Builder.defineMacro("__CHERI__", "1");
path: clang/lib/Frontend/InitPreprocessor.cpp
user: login: jrtc27
body: "1" is the default, might be worth dropping the explicit argument whilst touching this code as it has no real semantic meaning (beyond being non-zero so #if works)?
created_at: 2025-03-14T19:59:33Z
author_association: MEMBER
diff_hunk: @@ -115,9 +115,9 @@ int main(int, char**)
     test<__uint128_t>();
 #endif
 
-#if defined(__CHERI__) && !defined(__CHERI_PURE_CAPABILITY__)
-  test<__intcap_t>();
-  test<__uintcap_t>();
+#if defined(__CHERI_HYBRID__)
path: libcxx/test/std/utilities/function.objects/unord.hash/integral.pass.cpp
user: login: jrtc27
body: ```suggestion
#ifdef __CHERI_HYBRID__
```
created_at: 2025-03-14T20:00:23Z
author_association: MEMBER
diff_hunk: @@ -16,13 +25,22 @@ void* __capability x = 0;
 
 #if defined(__CHERI__)
 #pragma message("__CHERI__ defined")
-// CHECK-CHERI: warning: __CHERI__ defined
+// CHECK-CHERI: warning: __CHERI__ not defined
path: clang/test/Preprocessor/cheri-features.c
user: login: jrtc27
body: Move this into the #else? Weird to be here now.
created_at: 2025-03-14T20:03:18Z
author_association: MEMBER
diff_hunk: @@ -25,7 +25,7 @@ void* __capability x = 0;
 
 #if defined(__CHERI__)
path: clang/test/Preprocessor/cheri-features.c
user: login: brooksdavis
body: I've added the hybrid macro, it seems better to do the MIPS->RISC-V conversion in one go (the compiler command names also don't make sense to me)
created_at: 2025-03-14T22:01:43Z
author_association: MEMBER

PR comments:
user: login: brooksdavis
created_at: 2025-03-01T00:10:53Z
body: This should probably be split into two changes, the backwards compatible changes to `__CHERI__` use so we can pull them into CheriBSD and the breaking changes.
author_association: MEMBER
user: login: arichardson
created_at: 2025-03-01T02:54:14Z
body: I do wonder if we want to use __has_feature(cheri) ? Capabilities seems rather generic and may be difficult to upstream 
author_association: MEMBER
user: login: heshamelmatary
created_at: 2025-03-01T05:13:17Z
body: > I do wonder if we want to use __has_feature(cheri) ? Capabilities seems rather generic and may be difficult to upstream

I agree on that. It's rather confusing for systems like seL4 that already have their own notion/definition/types for a capability. 
author_association: MEMBER
user: login: heshamelmatary
created_at: 2025-03-05T08:03:14Z
body: 
I used to use `__CHERI__` whenever I wanted to guard or do something that applies to both purecap and hybrid. Some compatibility issues arise with using `__has_feature` with (old) GCC etc and broke legacy GCC builds. Those required some workarounds. eg:

```
#ifndef __has_feature
#define __has_feature(x) 0
#endif
```

This assumes all projects have some sort of a global shared header where this could be defined, but unfortunately this is not always the case.

Existing projects such as muslc [1], newlib, CHERI-Linux also still use `__CHERI__`. While an easy fix, but probably worth notifying the maintainers and/or fixing it ourselves.

[1] https://git.morello-project.org/search?search=__CHERI__&nav_source=navbar&project_id=122&group_id=6&search_code=true&repository_ref=morello%2Fmaster
author_association: MEMBER
user: login: bsdjhb
created_at: 2025-03-05T15:40:17Z
body: Note that this set of changes will actually make the GCC world happier as you can just use `#if defined(__CHERI__) || defined(__CHERI_HYBRID__)` in place of `#if __has_feature(cheri)` if desired once they are adopted.
author_association: CONTRIBUTOR
user: login: arichardson
created_at: 2025-03-05T17:11:18Z
body: > Note that this set of changes will actually make the GCC world happier as you can just use `#if defined(__CHERI__) || defined(__CHERI_HYBRID__)` in place of `#if __has_feature(cheri)` if desired once they are adopted.

And that change can be made now even if they want to support the older compiler versions.
author_association: MEMBER