diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12635,9 +12635,21 @@ if (!Var->isInvalidDecl() && Var->getType().getAddressSpace() == LangAS::opencl_constant && Var->getStorageClass() != SC_Extern && !Var->getInit()) { - Diag(Var->getLocation(), diag::err_opencl_constant_no_init); - Var->setInvalidDecl(); - return; + bool HasConstExprDefaultConstructor = false; + if (CXXRecordDecl *RD = Var->getType()->getAsCXXRecordDecl()) { + for (auto *Ctor : RD->ctors()) { + if (Ctor->isConstexpr() && Ctor->getNumParams() == 0 && + Ctor->getMethodQualifiers().getAddressSpace() == + LangAS::opencl_constant) { + HasConstExprDefaultConstructor = true; + } + } + } + if (!HasConstExprDefaultConstructor) { + Diag(Var->getLocation(), diag::err_opencl_constant_no_init); + Var->setInvalidDecl(); + return; + } } if (!Var->isInvalidDecl() && RealDecl->hasAttr()) { diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-constructors.clcpp b/clang/test/CodeGenOpenCLCXX/addrspace-constructors.clcpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenOpenCLCXX/addrspace-constructors.clcpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck %s + +// CHECK: %struct.X = type { i32 } + +// CHECK: @ci = dso_local addrspace(2) constant i32 0 +// CHECK: @gi = dso_local addrspace(1) global i32 0 +__constant int ci = 0; +__global int gi = 0; + +struct X { + int x; + + // Local variables are handled in local_addrspace_init.clcpp + // FIXME: __private and __generic constructors clash for __private variable + // X() /*__generic*/ = default; + X() __private : x(0) {} + X() __global : x(0) {} + constexpr X() __constant : x(0) {} + constexpr X(int x) __constant : x(x) {} +}; + +// CHECK: @cx1 = dso_local addrspace(2) constant %struct.X zeroinitializer +// CHECK: @cx2 = dso_local addrspace(2) constant %struct.X { i32 1 } +// CHECK: @gx = dso_local addrspace(1) global %struct.X zeroinitializer +__constant X cx1; +__constant X cx2(1); +__global X gx; + +// CHECK: @_ZZ1kE3cx1 = internal addrspace(2) constant %struct.X zeroinitializer +// CHECK: @_ZZ1kE3cx2 = internal addrspace(2) constant %struct.X { i32 1 } + +kernel void k() { + // Check that the constructor for px is executed + // CHECK: %px = alloca %struct.X + // CHECK-NEXT: call spir_func void @_ZN1XC1Ev(%struct.X* {{.*}}%px) + __private X px; + + __constant X cx1; + __constant X cx2(1); + // CHECK-NEXT: ret void +} diff --git a/clang/test/SemaOpenCLCXX/addrspace-constructors.clcpp b/clang/test/SemaOpenCLCXX/addrspace-constructors.clcpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaOpenCLCXX/addrspace-constructors.clcpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 %s -pedantic -verify -fsyntax-only + +__constant int g1; // expected-error {{variable in constant address space must be initialized}} +__constant int g2 = 0; + +struct X { + int x; + constexpr X() __constant : x(0) {} + constexpr X(int x) __constant : x(x) {} +}; + +//expected-note@+2{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const __generic Y' for 1st argument}} +//expected-note@+1{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to '__generic Y' for 1st argument}} +struct Y { + int y; + Y() __generic = default; // expected-note{{candidate constructor not viable: requires 0 arguments, but 1 was provided}} +}; + +kernel void k() { + __constant X cx1; + __constant X cx2(1); + __local X lx; + + __private Y py; + __constant Y cy1; // expected-error{{variable in constant address space must be initialized}} + __constant Y cy2(1); // expected-error{{no matching constructor for initialization of '__constant Y'}} +} + +struct Z { + int z; + // The address space is deduced to be __generic if omitted + Z() = default; // expected-note{{previous definition is here}} + Z() __generic = default; // expected-error {{constructor cannot be redeclared}} + + Z() __private = default; + Z() __local = default; + Z() __global = default; + // Can't default constexpr constructors + constexpr Z() __constant : z(0) {} +}; + +struct W { + int w; + constexpr W() __constant = default; // expected-error {{defaulted definition of default constructor is not constexpr}} +};