diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4289,17 +4289,36 @@ if (Sequence.step_begin() != Sequence.step_end()) Sequence.RewrapReferenceInitList(cv1T1, InitList); } - + // Perform address space compatibility check. + QualType cv1T1IgnoreAS = cv1T1; + if (T1Quals.hasAddressSpace()) { + Qualifiers T2Quals; + (void)S.Context.getUnqualifiedArrayType(InitList->getType(), T2Quals); + if (!T1Quals.isAddressSpaceSupersetOf(T2Quals)) { + Sequence.SetFailed( + InitializationSequence::FK_ReferenceInitDropsQualifiers); + return; + } + // Ignore address space of reference type at this point and perform address + // space conversion after the reference binding step. + cv1T1IgnoreAS = + S.Context.getQualifiedType(T1, T1Quals.withoutAddressSpace()); + } // Not reference-related. Create a temporary and bind to that. - InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1); + InitializedEntity TempEntity = + InitializedEntity::InitializeTemporary(cv1T1IgnoreAS); TryListInitialization(S, TempEntity, Kind, InitList, Sequence, TreatUnavailableAsInvalid); if (Sequence) { if (DestType->isRValueReferenceType() || - (T1Quals.hasConst() && !T1Quals.hasVolatile())) - Sequence.AddReferenceBindingStep(cv1T1, /*BindingTemporary=*/true); - else + (T1Quals.hasConst() && !T1Quals.hasVolatile())) { + Sequence.AddReferenceBindingStep(cv1T1IgnoreAS, + /*BindingTemporary=*/true); + if (T1Quals.hasAddressSpace()) + Sequence.AddQualificationConversionStep( + cv1T1, DestType->isRValueReferenceType() ? VK_XValue : VK_LValue); + } else Sequence.SetFailed( InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); } diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-references.cl b/clang/test/CodeGenOpenCLCXX/addrspace-references.cl --- a/clang/test/CodeGenOpenCLCXX/addrspace-references.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-references.cl @@ -1,8 +1,16 @@ -//RUN: %clang_cc1 %s -cl-std=clc++ -triple spir -emit-llvm -o - | FileCheck %s +//RUN: %clang_cc1 %s -cl-std=clc++ -triple spir -emit-llvm -o - -O0 | FileCheck %s + +typedef short short2 __attribute__((ext_vector_type(2))); int bar(const unsigned int &i); -// CHECK-LABEL: define{{.*}} spir_func void @_Z3foov() -void foo() { + +class C { +public: + void bar(const short2 &); +}; + +// CHECK-LABEL: define{{.*}} spir_func void @_Z6scalarv() +void scalar() { // The generic addr space reference parameter object will be bound // to a temporary value allocated in private addr space. We need an // addrspacecast before passing the value to the function. @@ -12,3 +20,14 @@ // CHECK: call spir_func i32 @_Z3barRU3AS4Kj(i32 addrspace(4)* align 4 dereferenceable(4) [[REG]]) bar(1); } + +// Test list initialization +// CHECK-LABEL: define{{.*}} spir_func void @_Z4listv() +void list() { + C c1; +// CHECK: [[REF:%.*]] = alloca <2 x i16> +// CHECK: store <2 x i16> , <2 x i16>* [[REF]] +// CHECK: [[REG:%[.a-z0-9]+]] = addrspacecast <2 x i16>* [[REF]] to <2 x i16> addrspace(4)* +// CHECK: call {{.*}}void @_ZNU3AS41C3barERU3AS4KDv2_s(%class.C addrspace(4)* {{.*}}, <2 x i16> addrspace(4)*{{.*}} [[REG]]) + c1.bar({1, 2}); +} diff --git a/clang/test/SemaOpenCLCXX/address-space-references.cl b/clang/test/SemaOpenCLCXX/address-space-references.cl --- a/clang/test/SemaOpenCLCXX/address-space-references.cl +++ b/clang/test/SemaOpenCLCXX/address-space-references.cl @@ -10,8 +10,20 @@ // can't detect this case and therefore fails. int bar(const unsigned int &i); +typedef short short2 __attribute__((ext_vector_type(2))); +class C { +public: + void gen(const short2 &); + void glob(__global const short2 &); //expected-note{{passing argument to parameter here}} + void nested_list(const short2 (&)[2]); +}; + void foo() { bar(1); // expected-error{{binding reference of type 'const __global unsigned int' to value of type 'int' changes address space}} + C c; + c.gen({1, 2}); + c.glob({1, 2}); //expected-error{{binding reference of type 'const __global short2' (vector of 2 'short' values) to value of type 'void' changes address space}} + c.nested_list({{1, 2}, {3, 4}}); } // Test addr space conversion with nested pointers