[clang] [Clang] Add __builtin_bswapg (PR #162433)

Oliver Hunt via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 18 22:02:29 PDT 2025


================
@@ -0,0 +1,212 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
+
+void test_basic_type_checks() {
+  static_assert(__is_same(char, decltype(__builtin_bswapg((char)0))), "");
+  static_assert(__is_same(unsigned char, decltype(__builtin_bswapg((unsigned char)0))), "");
+  static_assert(__is_same(short, decltype(__builtin_bswapg((short)0))), "");
+  static_assert(__is_same(unsigned short, decltype(__builtin_bswapg((unsigned short)0))), "");
+  static_assert(__is_same(int, decltype(__builtin_bswapg((int)0))), "");
+  static_assert(__is_same(unsigned int, decltype(__builtin_bswapg((unsigned int)0))), "");
+  static_assert(__is_same(long, decltype(__builtin_bswapg((long)0))), "");
+  static_assert(__is_same(unsigned long, decltype(__builtin_bswapg((unsigned long)0))), "");
+}
+
+template<typename T>
+void test_template_type_check() {
+  static_assert(__is_same(T, decltype(__builtin_bswapg(T{}))), 
+                "bswapg should return the same type as its argument");
+  constexpr T zero{};
+  constexpr T max = ~T{};
+  constexpr T one = T{1};
+    
+  static_assert(__is_same(T, decltype(__builtin_bswapg(zero))), "");
+  static_assert(__is_same(T, decltype(__builtin_bswapg(max))), "");
+  static_assert(__is_same(T, decltype(__builtin_bswapg(one))), "");
+}
+template void test_template_type_check<char>();
+template void test_template_type_check<unsigned char>();
+template void test_template_type_check<short>();
+template void test_template_type_check<unsigned short>();
+template void test_template_type_check<int>();
+template void test_template_type_check<unsigned int>();
+template void test_template_type_check<long>();
+template void test_template_type_check<unsigned long>();
+
+void test_lambda_type_checks() {
+  auto lambda = [](auto x) {
+    static_assert(__is_same(decltype(x), decltype(__builtin_bswapg(x))), 
+                  "bswapg in lambda should preserve type");
+    return __builtin_bswapg(x);
+  };
+  auto result_long = lambda(42UL);
+  static_assert(__is_same(unsigned long, decltype(result_long)), "");
+    
+  auto result_int = lambda(42);
+  static_assert(__is_same(int, decltype(result_int)), "");
+    
+  auto result_short = lambda(static_cast<short>(42));
+  static_assert(__is_same(short, decltype(result_short)), "");
+
+  auto result_char = lambda(static_cast<char>(42));
+  static_assert(__is_same(char, decltype(result_char)), "");
+}
+
+decltype(auto) test_decltype_auto(int x) {
+  return __builtin_bswapg(x);
+}
+
+void test_decltype_auto_check() {
+  int x = 42;
+  auto result = test_decltype_auto(x);
+  static_assert(__is_same(int, decltype(result)), "");
+}
+
+template<auto Value>
+struct ValueTemplateTypeTest {
+  using value_type = decltype(Value);
+  using result_type = decltype(__builtin_bswapg(Value));
+    
+  static constexpr bool type_matches = __is_same(value_type, result_type);
+  static_assert(type_matches, "Value template bswapg should preserve type");
+    
+  static constexpr auto swapped_value = __builtin_bswapg(Value);
+};
+
+template<auto... Values>
+void test_template_pack_types() {
+  static_assert((__is_same(decltype(Values), decltype(__builtin_bswapg(Values))) && ...), "All pack elements should preserve type");
+}
+
+template struct ValueTemplateTypeTest<0x1234>;
+template struct ValueTemplateTypeTest<0x12345678UL>;
+template struct ValueTemplateTypeTest<(short)0x1234>;
+template struct ValueTemplateTypeTest<(char)0x12>;
+
+template<typename T>
+void test_invalid_type() {
+  __builtin_bswapg(T{}); // #invalid_type_use
+}
+
+void test_basic_errors() {
+  test_invalid_type<float>();
+  // expected-note at -1 {{in instantiation of function template specialization 'test_invalid_type<float>' requested here}}
+  // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'float')}}
+  
+  test_invalid_type<double>(); 
+  // expected-note at -1 {{in instantiation of function template specialization 'test_invalid_type<double>' requested here}}
+  // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'double')}}
+
+  test_invalid_type<void*>(); 
+  // expected-note at -1 {{in instantiation of function template specialization 'test_invalid_type<void *>' requested here}}
+  // expected-error@#invalid_type_use {{1st argument must be a scalar integer type (was 'void *')}}
+}
+
+template<typename T>
+auto test_dependent_context(T value) -> decltype(__builtin_bswapg(value)) { // #dependent_use
+  return __builtin_bswapg(value); 
+}
+
+void test_dependent_errors() {
+  test_dependent_context(1.0f); 
+  // expected-error at -1 {{no matching function for call to 'test_dependent_context'}}
+  // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = float]: 1st argument must be a scalar integer type (was 'float')}}
+  test_dependent_context(1.0l); 
+  // expected-error at -1 {{no matching function for call to 'test_dependent_context'}}
+  // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = long double]: 1st argument must be a scalar integer type (was 'long double')}}
+  test_dependent_context("hello"); 
+  // expected-error at -1 {{no matching function for call to 'test_dependent_context'}}
+  // expected-note@#dependent_use {{candidate template ignored: substitution failure [with T = const char *]: 1st argument must be a scalar integer type (was 'const char *')}}
+}
+
+void test_lambda_errors() {
+  auto lambda = [](auto x) {
+    return __builtin_bswapg(x); // #lambda_use
+  };
+  
+  lambda(1.0f);
+  // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'float')}}
+  // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<float>' requested here}}
+  lambda(1.0l);
+  // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'long double')}}
+  // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<long double>' requested here}}
+  lambda("hello");
+  // expected-error@#lambda_use {{1st argument must be a scalar integer type (was 'const char *')}}
+  // expected-note at -2 {{in instantiation of function template specialization 'test_lambda_errors()::(anonymous class)::operator()<const char *>' requested here}}
+}
+
+void test_argument_count_errors() {
+  int h14 = __builtin_bswapg(1, 2); // expected-error {{too many arguments to function call, expected 1, have 2}}
+}
----------------
ojhunt wrote:

Paranoia test:

```cpp
template <class... Args> void test_variadic_template_argument_count(Args... args) {
   int result = __builtin_bswapg(args...);
}
void test_variadic_template_args() {
  test_variadic_template_argument_count();
  test_variadic_template_argument_count(1);
  test_variadic_template_argument_count(1, 2);
}
```

I _think_ that should already work via the dependent type check, but I'm always somewhat paranoid about the wonders of templates :D

https://github.com/llvm/llvm-project/pull/162433


More information about the cfe-commits mailing list