Skip to content

Conversation

piotrrak
Copy link

@piotrrak piotrrak commented Aug 13, 2025

The default OpenCL address-space was added for function types, which was
breaking transform type builtins for function types, in particular:

  • __remove_reference_t
  • __remove_cvref
  • __remove_pointer

This change fixes SemaCXX/type-traits.cpp pass for clc++ dialect.
(In feature set of clc++ and extension - ie. no VLA, _Atomic etc...)

There is still unaddressed issue with address space of member-fn-ptr
in __is_same trait builtin as address-space specified by user is
ignored on such types.

This is separate unrelated issue and won't be addressed in this change.

Note for reviewers:

I consider this change non-trivial and might have deeper consequnces in OpenCL drivers codegen in areas of intriniscs and blocks lowering CG, but it might affect vendor passes.

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

Copy link

github-actions bot commented Aug 13, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@piotrrak piotrrak force-pushed the openclcpp-type-traits branch from 202c673 to a2b7b6e Compare August 13, 2025 23:47
@piotrrak
Copy link
Author

piotrrak commented Aug 14, 2025

Should wait for #153459 to make enabling SemaCXX/type-traits.cpp possible.

@piotrrak piotrrak force-pushed the openclcpp-type-traits branch from a2b7b6e to bfd989d Compare August 14, 2025 08:48
@piotrrak piotrrak marked this pull request as ready for review August 15, 2025 12:23
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 15, 2025

@llvm/pr-subscribers-clang

Author: None (piotrrak)

Changes

The default OpenCL address-space was added for function types, which was
breaking transform type builtins for function types, in particular:

  • __remove_reference_t
  • __remove_cvref
  • __remove_pointer

This change fixes SemaCXX/type-traits.cpp pass for clc++ dialect.
(In feature set of clc++ and extension - ie. no VLA, _Atomic etc...)

There is still unaddressed issue with address space of member-fn-ptr
in __is_same trait builtin as address-space specified by user is
ignored on such types.

This is separate unrelated issue and won't be addressed in this change.

Note for reviewers:

I consider this change non-trivial and might have deeper consequnces in OpenCL drivers codegen in areas of intriniscs and blocks lowering CG, but it might affect vendor passes.


Patch is 81.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/153508.diff

3 Files Affected:

  • (modified) clang/lib/Sema/SemaType.cpp (+6-4)
  • (modified) clang/test/SemaCXX/type-traits.cpp (+462-29)
  • (added) clang/test/SemaOpenCLCXX/address-space-traits.clcpp (+29)
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index d745cdbf0526f..70a52947ebad9 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1794,9 +1794,11 @@ bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) {
 }
 
 // Helper to deduce addr space of a pointee type in OpenCL mode.
-static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType) {
+static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType,
+                                             bool IsBlock) {
   if (!PointeeType->isUndeducedAutoType() && !PointeeType->isDependentType() &&
       !PointeeType->isSamplerT() &&
+      (!PointeeType->isFunctionType() || IsBlock) &&
       !PointeeType.hasAddressSpace())
     PointeeType = S.getASTContext().getAddrSpaceQualType(
         PointeeType, S.getASTContext().getDefaultOpenCLPointeeAddrSpace());
@@ -1835,7 +1837,7 @@ QualType Sema::BuildPointerType(QualType T,
     T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false);
 
   if (getLangOpts().OpenCL)
-    T = deduceOpenCLPointeeAddrSpace(*this, T);
+    T = deduceOpenCLPointeeAddrSpace(*this, T, /*IsBlock*/ false);
 
   // In WebAssembly, pointers to reference types and pointers to tables are
   // illegal.
@@ -1912,7 +1914,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
     T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
 
   if (getLangOpts().OpenCL)
-    T = deduceOpenCLPointeeAddrSpace(*this, T);
+    T = deduceOpenCLPointeeAddrSpace(*this, T, /*IsBlock*/ false);
 
   // In WebAssembly, references to reference types and tables are illegal.
   if (getASTContext().getTargetInfo().getTriple().isWasm() &&
@@ -2767,7 +2769,7 @@ QualType Sema::BuildBlockPointerType(QualType T,
     return QualType();
 
   if (getLangOpts().OpenCL)
-    T = deduceOpenCLPointeeAddrSpace(*this, T);
+    T = deduceOpenCLPointeeAddrSpace(*this, T, /*IsBlock*/ true);
 
   return Context.getBlockPointerType(T);
 }
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 3f0124755c674..96298f9156f90 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1,8 +1,19 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted -Wno-c++17-extensions  %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted -Wno-c++17-extensions  %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++17 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted  %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++20 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted  %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify=expected,expected-noncl -std=gnu++11 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted -Wno-c++17-extensions  %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify=expected,expected-noncl -std=gnu++14 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted -Wno-c++17-extensions  %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify=expected,expected-noncl -std=gnu++17 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted  %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify=expected,expected-noncl -std=gnu++20 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted  %s
+// RUN: %clang_cc1 -triple spirv64-none-none -fsyntax-only -fno-rtti -verify=expected,expected-cl -cl-std=clc++2021 -Wno-deprecated-builtins -Wno-defaulted-function-deleted -cl-ext=+__cl_clang_variadic_functions,+__cl_clang_function_pointers,+__cl_clang_bitfields -DVANILLAOPENCLCPLUSPLUS %s
+// RUN: %clang_cc1 -triple spirv64-none-none -fsyntax-only -fno-rtti -verify=expected,expected-cl -cl-std=clc++2021 -Wno-deprecated-builtins -Wno-defaulted-function-deleted -cl-ext=+__cl_clang_variadic_functions,+__cl_clang_function_pointers,+__cl_clang_bitfields -DEXTOPENCLCPLUSPLUS %s
+
+#if defined(EXTOPENCLCPLUSPLUS)
+#pragma OPENCL EXTENSION __cl_clang_variadic_functions : enable
+#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
+#pragma OPENCL EXTENSION __cl_clang_bitfields : enable
+#endif
 
+#if defined(EXTOPENCLCPLUSPLUS) || defined(VANILLAOPENCLCPLUSPLUS)
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+#endif
 
 struct NonPOD { NonPOD(int); };
 typedef NonPOD NonPODAr[10];
@@ -111,9 +122,16 @@ class  HasProt { protected: int prot; };
 struct HasRef { int i; int& ref; HasRef() : i(0), ref(i) {} };
 struct HasRefAggregate { int i; int& ref; };
 struct HasNonPOD { NonPOD np; };
+#if !defined(VANILLAOPENCLCPLUSPLUS)
+struct HasVirt { virtual void Virt() {}; };
+#else
 struct HasVirt { virtual void Virt() {}; };
+//expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}}
+#endif
 typedef NonPOD NonPODAr[10];
+#if !defined(VANILLAOPENCLCPLUSPLUS)
 typedef HasVirt VirtAr[10];
+#endif
 typedef NonPOD NonPODArNB[];
 union NonPODUnion { int i; Derives n; };
 struct DerivesHasCons : HasCons {};
@@ -123,7 +141,9 @@ struct DerivesHasDest : HasDest {};
 struct DerivesHasPriv : HasPriv {};
 struct DerivesHasProt : HasProt {};
 struct DerivesHasRef : HasRef {};
+#if !defined(VANILLAOPENCLCPLUSPLUS)
 struct DerivesHasVirt : HasVirt {};
+#endif
 struct DerivesHasMoveCtor : HasMoveCtor {};
 
 struct HasNoThrowCopyAssign {
@@ -161,9 +181,14 @@ struct HasMultipleNoThrowCopy {
   HasMultipleNoThrowCopy(volatile HasMultipleNoThrowCopy&) throw();
 };
 
+#if defined(VANILLAOPENCLCPLUSPLUS)
+struct HasVirtDest { virtual ~HasVirtDest(); };
+//expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}}
+#else
 struct HasVirtDest { virtual ~HasVirtDest(); };
 struct DerivedVirtDest : HasVirtDest {};
 typedef HasVirtDest VirtDestAr[1];
+#endif
 
 class AllPrivate {
   AllPrivate() throw();
@@ -244,13 +269,17 @@ void is_pod()
   static_assert(!__is_pod(HasMoveAssign));
   static_assert(!__is_pod(HasDest));
   static_assert(!__is_pod(HasRef));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_pod(HasVirt));
+#endif
   static_assert(!__is_pod(DerivesHasCons));
   static_assert(!__is_pod(DerivesHasCopyAssign));
   static_assert(!__is_pod(DerivesHasMoveAssign));
   static_assert(!__is_pod(DerivesHasDest));
   static_assert(!__is_pod(DerivesHasRef));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_pod(DerivesHasVirt));
+#endif
   static_assert(!__is_pod(NonPOD));
   static_assert(!__is_pod(HasNonPOD));
   static_assert(!__is_pod(NonPODAr));
@@ -266,11 +295,13 @@ void is_pod()
 }
 
 typedef Empty EmptyAr[10];
+#if !defined(VANILLAOPENCLCPLUSPLUS)
 struct Bit0 { int : 0; };
 struct Bit0Cons { int : 0; Bit0Cons(); };
 struct AnonBitOnly { int : 3; };
 struct BitOnly { int x : 3; };
 struct DerivesVirt : virtual POD {};
+#endif
 
 void is_empty()
 {
@@ -284,8 +315,10 @@ void is_empty()
   static_assert(__is_empty(HasOp));
   static_assert(__is_empty(HasConv));
   static_assert(__is_empty(HasAssign));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(__is_empty(Bit0));
   static_assert(__is_empty(Bit0Cons));
+#endif
 
   static_assert(!__is_empty(Int));
   static_assert(!__is_empty(POD));
@@ -293,9 +326,11 @@ void is_empty()
   static_assert(!__is_empty(IncompleteUnion));
   static_assert(!__is_empty(EmptyAr));
   static_assert(!__is_empty(HasRef));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_empty(HasVirt));
   static_assert(!__is_empty(AnonBitOnly));
   static_assert(!__is_empty(BitOnly));
+#endif
   static_assert(!__is_empty(void));
   static_assert(!__is_empty(IntArNB));
   static_assert(!__is_empty(HasAnonymousUnion));
@@ -442,13 +477,17 @@ void is_final()
 }
 
 
+#if !defined(VANILLAOPENCLCPLUSPLUS)
 typedef HasVirt Polymorph;
 struct InheritPolymorph : Polymorph {};
+#endif
 
 void is_polymorphic()
 {
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(__is_polymorphic(Polymorph));
   static_assert(__is_polymorphic(InheritPolymorph));
+#endif
 
   static_assert(!__is_polymorphic(int));
   static_assert(!__is_polymorphic(Union));
@@ -590,8 +629,10 @@ void is_aggregate()
   static_assert(!__is_aggregate(HasProt));
   static_assert(__is_aggregate(HasRefAggregate));
   static_assert(__is_aggregate(HasNonPOD));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_aggregate(HasVirt));
   static_assert(__is_aggregate(VirtAr));
+#endif
   static_assert(__is_aggregate(HasInClassInit) == TrueAfterCpp11);
   static_assert(!__is_aggregate(HasPrivateBase));
   static_assert(!__is_aggregate(HasProtectedBase));
@@ -747,8 +788,10 @@ void is_bounded_array(int n) {
   static_assert(!__is_bounded_array(void *));
   static_assert(!__is_bounded_array(cvoid *));
 
+#if !defined(VANILLAOPENCLCPLUSPLUS) && !defined(EXTOPENCLCPLUSPLUS)
   int t32[n];
   (void)__is_bounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported in '__is_bounded_array'}}
+#endif
 }
 
 void is_unbounded_array(int n) {
@@ -780,8 +823,10 @@ void is_unbounded_array(int n) {
   static_assert(!__is_unbounded_array(void *));
   static_assert(!__is_unbounded_array(cvoid *));
 
+#if !defined(VANILLAOPENCLCPLUSPLUS) && !defined(EXTOPENCLCPLUSPLUS)
   int t32[n];
   (void)__is_unbounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported in '__is_unbounded_array'}}
+#endif
 }
 
 template <typename T> void tmpl_func(T&) {}
@@ -794,10 +839,15 @@ template <typename T> struct type_wrapper {
 
 void is_function()
 {
+#if !defined(VANILLAOPENCLCPLUSPLUS)&& !defined(EXTOPENCLCPLUSPLUS)
+  // Requires RTTI
   static_assert(__is_function(type_wrapper<void(void)>::type));
   static_assert(__is_function(typeof(tmpl_func<int>)));
+#endif
 
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   typedef void (*ptr_to_func_type)(void);
+#endif
 
   static_assert(!__is_function(void));
   static_assert(!__is_function(cvoid));
@@ -821,10 +871,12 @@ void is_function()
   static_assert(!__is_function(Enum));
   static_assert(!__is_function(void*));
   static_assert(!__is_function(cvoid*));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_function(void(*)()));
   static_assert(!__is_function(ptr_to_func_type));
   static_assert(!__is_function(type_wrapper<void(void)>::ptrtype));
   static_assert(!__is_function(type_wrapper<void(void)>::reftype));
+#endif
 }
 
 void is_reference()
@@ -908,7 +960,9 @@ void is_object()
   static_assert(__is_object(ClassType));
   static_assert(__is_object(Enum));
 
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_object(type_wrapper<void(void)>::type));
+#endif
   static_assert(!__is_object(int&));
   static_assert(!__is_object(void));
 }
@@ -951,9 +1005,11 @@ void is_compound()
 {
   static_assert(__is_compound(void*));
   static_assert(__is_compound(cvoid*));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(__is_compound(void (*)()));
   static_assert(__is_compound(int StructWithMembers::*));
   static_assert(__is_compound(void (StructWithMembers::*)()));
+#endif
   static_assert(__is_compound(int&));
   static_assert(__is_compound(Union));
   static_assert(__is_compound(UnionAr));
@@ -997,7 +1053,10 @@ void is_pointer()
   static_assert(__is_pointer(Union*));
   static_assert(__is_pointer(UnionAr*));
   static_assert(__is_pointer(StructWithMembers*));
+
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(__is_pointer(void (*)()));
+#endif
 
   static_assert(!__is_pointer(void));
   static_assert(!__is_pointer(cvoid));
@@ -1013,7 +1072,9 @@ void is_pointer()
   static_assert(!__is_pointer(UnionAr));
   static_assert(!__is_pointer(StructWithMembers));
   static_assert(!__is_pointer(int StructWithMembers::*));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_pointer(void (StructWithMembers::*) ()));
+#endif
 }
 
 void is_member_object_pointer()
@@ -1022,7 +1083,9 @@ void is_member_object_pointer()
 
   static_assert(__is_member_object_pointer(int StructWithMembers::*));
 
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_member_object_pointer(void (StructWithMembers::*) ()));
+#endif
   static_assert(!__is_member_object_pointer(void*));
   static_assert(!__is_member_object_pointer(cvoid*));
   static_assert(!__is_member_object_pointer(cvoid*));
@@ -1049,14 +1112,18 @@ void is_member_object_pointer()
   static_assert(!__is_member_object_pointer(Union));
   static_assert(!__is_member_object_pointer(UnionAr));
   static_assert(!__is_member_object_pointer(StructWithMembers));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_member_object_pointer(void (*)()));
+#endif
 }
 
 void is_member_function_pointer()
 {
   StructWithMembers x;
 
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(__is_member_function_pointer(void (StructWithMembers::*) ()));
+#endif
 
   static_assert(!__is_member_function_pointer(int StructWithMembers::*));
   static_assert(!__is_member_function_pointer(void*));
@@ -1085,7 +1152,9 @@ void is_member_function_pointer()
   static_assert(!__is_member_function_pointer(Union));
   static_assert(!__is_member_function_pointer(UnionAr));
   static_assert(!__is_member_function_pointer(StructWithMembers));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_member_function_pointer(void (*)()));
+#endif
 }
 
 void is_member_pointer()
@@ -1093,7 +1162,9 @@ void is_member_pointer()
   StructWithMembers x;
 
   static_assert(__is_member_pointer(int StructWithMembers::*));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(__is_member_pointer(void (StructWithMembers::*) ()));
+#endif
 
   static_assert(!__is_member_pointer(void*));
   static_assert(!__is_member_pointer(cvoid*));
@@ -1121,7 +1192,9 @@ void is_member_pointer()
   static_assert(!__is_member_pointer(Union));
   static_assert(!__is_member_pointer(UnionAr));
   static_assert(!__is_member_pointer(StructWithMembers));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_member_pointer(void (*)()));
+#endif
 }
 
 void is_const()
@@ -1392,12 +1465,14 @@ struct CppStructNonStandardByBase : CStruct {
   int three;
   int four;
 };
+#if !defined(VANILLAOPENCLCPLUSPLUS)
 struct CppStructNonStandardByVirt : CStruct {
   virtual void method() {}
 };
 struct CppStructNonStandardByMemb : CStruct {
   CppStructNonStandardByVirt member;
 };
+#endif
 struct CppStructNonStandardByProt : CStruct {
   int five;
 protected:
@@ -1429,8 +1504,10 @@ void is_standard_layout()
 
   typedef CppStructNonStandardByBase CppStructNonStandardByBaseAr[4];
 
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_standard_layout(CppStructNonStandardByVirt));
   static_assert(!__is_standard_layout(CppStructNonStandardByMemb));
+#endif
   static_assert(!__is_standard_layout(CppStructNonStandardByProt));
   static_assert(!__is_standard_layout(CppStructNonStandardByVirtBase));
   static_assert(!__is_standard_layout(CppStructNonStandardByBase));
@@ -1445,6 +1522,7 @@ void is_standard_layout()
   static_assert(!__is_standard_layout(void));
   static_assert(!__is_standard_layout(const volatile void));
 
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   struct HasAnonEmptyBitfield { int : 0; };
   struct HasAnonBitfield { int : 4; };
   struct DerivesFromBitfield : HasAnonBitfield {};
@@ -1456,6 +1534,7 @@ void is_standard_layout()
   static_assert(__is_standard_layout(DerivesFromBitfield));
   static_assert(!__is_standard_layout(DerivesFromBitfieldWithBitfield));
   static_assert(!__is_standard_layout(DerivesFromBitfieldTwice));
+#endif
 
   struct Empty {};
   struct HasEmptyBase : Empty {};
@@ -1467,7 +1546,9 @@ void is_standard_layout()
   struct HasEmptyBaseAsSubobjectOfMember3 : Empty { HoldsEmptyBase e[2]; };
   struct HasEmptyIndirectBaseAsMember : HasEmptyBase { Empty e; };
   struct HasEmptyIndirectBaseAsSecondMember : HasEmptyBase { int n; Empty e; };
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   struct HasEmptyIndirectBaseAfterBitfield : HasEmptyBase { int : 4; Empty e; };
+#endif
 
   static_assert(__is_standard_layout(Empty));
   static_assert(__is_standard_layout(HasEmptyBase));
@@ -1478,7 +1559,9 @@ void is_standard_layout()
   static_assert(!__is_standard_layout(HasEmptyBaseAsSubobjectOfMember3));
   static_assert(!__is_standard_layout(HasEmptyIndirectBaseAsMember));
   static_assert(__is_standard_layout(HasEmptyIndirectBaseAsSecondMember));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(!__is_standard_layout(HasEmptyIndirectBaseAfterBitfield)); // FIXME: standard bug?
+#endif
 
   struct StructWithEmptyFields {
     int n;
@@ -1515,12 +1598,14 @@ struct CppStructNonStandardByBase2 : CStruct2 {
   int three;
   int four;
 };
+#if !defined(VANILLAOPENCLCPLUSPLUS)
 struct CppStructNonStandardByVirt2 : CStruct2 {
   virtual void method() {}
 };
 struct CppStructNonStandardByMemb2 : CStruct2 {
   CppStructNonStandardByVirt member;
 };
+#endif
 struct CppStructNonStandardByProt2 : CStruct2 {
   int five;
 protected:
@@ -1579,6 +1664,7 @@ struct CStructNested2 {
   int b2;
 };
 
+#if !defined(VANILLAOPENCLCPLUSPLUS)
 struct CStructWithBitfelds {
   int a : 5;
   int : 0;
@@ -1598,6 +1684,7 @@ struct CStructWithBitfelds4 {
   EnumLayout a : 5;
   int : 0;
 };
+#endif
 
 union UnionLayout {
   int a;
@@ -1694,22 +1781,29 @@ void is_layout_compatible(int n)
   static_assert(__is_layout_compatible(int, volatile int));
   static_assert(__is_layout_compatible(const int, volatile int));
   static_assert(__is_layout_compatible(int *, int * __restrict));
+#if !defined(VANILLAOPENCLCPLUSPLUS) && !defined(EXTOPENCLCPLUSPLUS)
   // Note: atomic qualification matters for layout compatibility.
+  // Note: OpenCL no _Atomic
   static_assert(!__is_layout_compatible(int, _Atomic int));
   static_assert(__is_layout_compatible(_Atomic(int), _Atomic int));
+#endif
   static_assert(!__is_layout_compatible(int, unsigned int));
   static_assert(!__is_layout_compatible(char, unsigned char));
   static_assert(!__is_layout_compatible(char, signed char));
   static_assert(!__is_layout_compatible(unsigned char, signed char));
   static_assert(__is_layout_compatible(int[], int[]));
   static_assert(__is_layout_compatible(int[2], int[2]));
+  // OpenCLCPP: No VLA
+#if !defined(VANILLAOPENCLCPLUSPLUS) && !defined(EXTOPENCLCPLUSPLUS)
   static_assert(!__is_layout_compatible(int[n], int[2]));
   // expected-error@-1 {{variable length arrays are not supported in '__is_layout_compatible'}}
   static_assert(!__is_layout_compatible(int[n], int[n]));
   // expected-error@-1 {{variable length arrays are not supported in '__is_layout_compatible'}}
   // expected-error@-2 {{variable length arrays are not supported in '__is_layout_compatible'}}
+#endif
   static_assert(__is_layout_compatible(int&, int&));
   static_assert(!__is_layout_compatible(int&, char&));
+#if !defined(VANILLAOPENCLCPLUSPLUS)
   static_assert(__is_layout_compatible(void(int), void(int)));
   static_assert(!__is_layout_compatible(void(int), void(char)));
   static_assert(__is_layout_compatible(void(&)(int), void(&)(int)));
@@ -1725,7 +1819,9 @@ void is_layout_compatible(int n)
   // expected-warning@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
   static_assert(!__is_layout_compatible(const function_type, const function_type2));
   // expected-warning@-1 {{'const' qualifier on function type 'function_type' (aka 'void ()') has no effect}}
-  // expected-warning@-2 {{'const' qualifier on function type 'function_type2' (aka 'void (char)') has no effect}}
+  // expected-noncl-warning@-2 {{'const' qualifier on function type 'function_type2' (aka 'void (char)') has no effect}}
+  // expected-cl-warning@-3 {{'const' qualifier on function type 'function_type2' (aka 'void (__private char)') has no effect}}
+#endif
   static_assert(__is_layout_compatible(CStruct, CStruct2));
   static_assert(__is_layout_compatible(CStruct, const CStruct2));
   static_assert(__is_layout_compatible(CStruct, volatile CStruct2));
@@ -1734,26 +1830,34 @@ void is_layout_compatible(int n)
   static_assert(__is_layout_compatible(CppEmptyStruct, CppEmptyStruct2));
   static_assert(__is_layout_compatible(CppStructStandard, CppStructStandard2));
   static_assert(!__is_layout_compatible(CppStructNonStandardByBase, CppStructNonStandardByBase2))...
[truncated]

OpenCL prohibits address-space on function, however it
default address-space is implicitly to all member decls.

This causes the lookup to fail find correct free function or free function
template as it is considered different declaration.

This change also makes sure that hidden friend definition doesn't have
associated address-space.

Without this change friend declaration would cause incorrect diagnostic:

'test/SemaCXX/friend.cpp Line 16: conflicting types for 'f'`

in case of prior definition of function f friend declaration was refering to

While bit unsatisfactory it was much easier to fix/remove address-space of
friend declaration since it is still required for friend of member function
decls.

This change also enables compilation of some of failing test exposing this defect.

It was originally exhibited by 'test/SemaCXX/type-traits.cpp', however this test
has currently other issues also related to the __cl_clang_function_pointers
extension and address-space inferrence preventing from enabling it by the defaut.
The default OpenCL address-space was added for function types, which was
breaking transform type builtins for function types, in particular:

- __remove_reference_t
- __remove_cvref
- __remove_pointer

This change fixes SemaCXX/type-traits.cpp pass for clc++ dialect.
(In feature set of clc++ and extension - ie. no VLA, _Atomic etc...)

There is still unaddressed issue with address space of member-fn-ptr
in __is_same trait builtin as address-space specified by user is
ignored on such types.

This is seperate unrelated issue and won't be addressed in this change.
@piotrrak piotrrak force-pushed the openclcpp-type-traits branch from 91e9efe to a36ee05 Compare August 22, 2025 20:36
@piotrrak
Copy link
Author

Rebased on top of #153459 @svenvh would you mind if I add you to review of this one too?

@piotrrak
Copy link
Author

Related to #140046

// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted -Wno-c++17-extensions %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++17 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++20 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify=expected,expected-noncl -std=gnu++11 -fblocks -Wno-deprecated-builtins -Wno-defaulted-function-deleted -Wno-c++17-extensions %s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit hesitant about the large number of #ifs added to this test; a sporadic guard would be fine I suppose, but with this many guards we'd need an opinion from the C++ maintainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants