[clang] b6259ec - [Clang] Export CanPassInRegisters as a type trait

Roy Jacobson via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 13 09:16:30 PST 2023


Author: Roy Jacobson
Date: 2023-02-13T19:16:23+02:00
New Revision: b6259eca16f6c923d87a1ca1d424931e37d6871a

URL: https://github.com/llvm/llvm-project/commit/b6259eca16f6c923d87a1ca1d424931e37d6871a
DIFF: https://github.com/llvm/llvm-project/commit/b6259eca16f6c923d87a1ca1d424931e37d6871a.diff

LOG: [Clang] Export CanPassInRegisters as a type trait

While working on D140664, I thought it would be nice to be able to write tests
for parameter passing ABI. Currently we test this by dumping the AST and
matching the results which makes it hard to write new tests.
Adding this builtin will allow writing better ABI tests which
can help improve our coverage in this area.

While less useful, maybe some users would also find it useful for asserting
against pessimisations for their classes.

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D141775

Added: 
    

Modified: 
    clang/docs/LanguageExtensions.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Basic/TokenKinds.def
    clang/lib/Sema/SemaExprCXX.cpp
    clang/test/SemaCXX/type-traits.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 84d5b0ed98108..20c8bb5de0443 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1401,6 +1401,10 @@ The following type trait primitives are supported by Clang. Those traits marked
 * ``__array_extent(type, dim)`` (Embarcadero):
   The ``dim``'th array bound in the type ``type``, or ``0`` if
   ``dim >= __array_rank(type)``.
+* ``__can_pass_in_regs`` (C++)
+  Returns whether a class can be passed in registers under the current
+  ABI. This type can only be applied to unqualified class types.
+  This is not a portable type trait.
 * ``__has_nothrow_assign`` (GNU, Microsoft, Embarcadero):
   Deprecated, use ``__is_nothrow_assignable`` instead.
 * ``__has_nothrow_move_assign`` (GNU, Microsoft):

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9b9ec23a2f21f..b658ad71e63a1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11794,4 +11794,8 @@ def note_unsafe_buffer_variable_fixit : Note<
   "change type of '%0' to '%select{std::span|std::array|std::span::iterator}1' to preserve bounds information">;
 def err_loongarch_builtin_requires_la32 : Error<
   "this builtin requires target: loongarch32">;
+
+def err_builtin_pass_in_regs_non_class : Error<
+  "argument %0 is not an unqualified class type">;
+
 } // end of sema component.

diff  --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 96feae991ccbc..6d35f1bb31fcd 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -523,6 +523,7 @@ TYPE_TRAIT_1(__is_unbounded_array, IsUnboundedArray, KEYCXX)
 TYPE_TRAIT_1(__is_nullptr, IsNullPointer, KEYCXX)
 TYPE_TRAIT_1(__is_scoped_enum, IsScopedEnum, KEYCXX)
 TYPE_TRAIT_1(__is_referenceable, IsReferenceable, KEYCXX)
+TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX)
 TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
 
 // Embarcadero Expression Traits

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ef012770747ca..eb9a3e65763f2 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4885,6 +4885,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
   case UTT_IsLiteral:
   // By analogy, is_trivially_relocatable imposes the same constraints.
   case UTT_IsTriviallyRelocatable:
+  case UTT_CanPassInRegs:
   // Per the GCC type traits documentation, T shall be a complete type, cv void,
   // or an array of unknown bound. But GCC actually imposes the same constraints
   // as above.
@@ -5373,6 +5374,11 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
     return T.isTriviallyRelocatableType(C);
   case UTT_IsReferenceable:
     return T.isReferenceable();
+  case UTT_CanPassInRegs:
+    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl(); RD && !T.hasQualifiers())
+      return RD->canPassInRegisters();
+    Self.Diag(KeyLoc, diag::err_builtin_pass_in_regs_non_class) << T;
+    return false;
   }
 }
 

diff  --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 76a67252c9410..7d425acb56813 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -3055,6 +3055,36 @@ static_assert(__is_trivially_relocatable(TrivialAbiNontrivialMoveCtor[]), "");
 
 } // namespace is_trivially_relocatable
 
+namespace can_pass_in_regs {
+
+struct A { };
+
+struct B {
+  ~B();
+};
+
+struct C; // expected-note {{forward declaration}}
+
+union D {
+  int x;
+};
+
+static_assert(__can_pass_in_regs(A), "");
+static_assert(__can_pass_in_regs(A), "");
+static_assert(!__can_pass_in_regs(B), "");
+static_assert(__can_pass_in_regs(D), "");
+
+void test_errors() {
+  (void)__can_pass_in_regs(const A); // expected-error {{not an unqualified class type}}
+  (void)__can_pass_in_regs(A&); // expected-error {{not an unqualified class type}}
+  (void)__can_pass_in_regs(A&&); // expected-error {{not an unqualified class type}}
+  (void)__can_pass_in_regs(const A&); // expected-error {{not an unqualified class type}}
+  (void)__can_pass_in_regs(C); // expected-error {{incomplete type}}
+  (void)__can_pass_in_regs(int); // expected-error {{not an unqualified class type}}
+  (void)__can_pass_in_regs(int&); // expected-error {{not an unqualified class type}}
+}
+}
+
 struct S {};
 template <class T> using remove_const_t = __remove_const(T);
 


        


More information about the cfe-commits mailing list