olestrohm created this revision. olestrohm added reviewers: Anastasia, rjmccall. olestrohm added a project: clang. Herald added subscribers: cfe-commits, yaxunl.
When you have a templated constructor with an R-value reference the compiler implicitly creates a copy and move constructor through the template constructor, and the copy constructor created this way was missing an address space in the reference parameter. I've come up with this fix that deduces the address space for the reference parameter right before it's created, and a corresponding test. The test is quite big, but rep_outer is necessary to force the compiler to create the copy constructor, and the two template structs are partly for readability. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D83665 Files: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaTemplateDeduction.cpp clang/lib/Sema/SemaType.cpp clang/test/SemaOpenCLCXX/address-space-templates.cl
Index: clang/test/SemaOpenCLCXX/address-space-templates.cl =================================================================== --- clang/test/SemaOpenCLCXX/address-space-templates.cl +++ clang/test/SemaOpenCLCXX/address-space-templates.cl @@ -22,10 +22,28 @@ __private T ii; // expected-error{{conflicting address space qualifiers are provided between types '__private T' and '__global int'}} } +template <class _Tp> struct remove_reference { typedef _Tp type; }; +template <class _Tp> struct remove_reference<_Tp &> { typedef _Tp type; }; +template <class _Tp> struct as_pointer { + typedef typename remove_reference<_Tp>::type* type; +}; + +struct rep { + // CHECK |-CXXConstructorDecl {{.*}} rep 'void (const __generic rep &__private) __generic' + template<class U, class = typename as_pointer<U>::type> + rep(U&& v) {} +}; + +struct rep_outer : private rep { + rep_outer() + : rep(0) {} +}; + void bar() { S<const __global int> sintgl; // expected-note{{in instantiation of template class 'S<const __global int>' requested here}} foo1<__local int>(1); // expected-error{{no matching function for call to 'foo1'}} foo2<__global int>(0); foo3<__global int>(); // expected-note{{in instantiation of function template specialization 'foo3<__global int>' requested here}} + rep_outer r; } Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -2036,13 +2036,13 @@ } // Helper to deduce addr space of a pointee type in OpenCL mode. -static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType) { +QualType Sema::deduceOpenCLPointeeAddrSpace(QualType PointeeType) { if (!PointeeType->isUndeducedAutoType() && !PointeeType->isDependentType() && !PointeeType->isSamplerT() && !PointeeType.hasAddressSpace()) - PointeeType = S.getASTContext().getAddrSpaceQualType( + PointeeType = getASTContext().getAddrSpaceQualType( PointeeType, - S.getLangOpts().OpenCLCPlusPlus || S.getLangOpts().OpenCLVersion == 200 + getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion == 200 ? LangAS::opencl_generic : LangAS::opencl_private); return PointeeType; @@ -2085,7 +2085,7 @@ T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false); if (getLangOpts().OpenCL) - T = deduceOpenCLPointeeAddrSpace(*this, T); + T = deduceOpenCLPointeeAddrSpace(T); // Build the pointer type. return Context.getPointerType(T); @@ -2148,7 +2148,7 @@ T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true); if (getLangOpts().OpenCL) - T = deduceOpenCLPointeeAddrSpace(*this, T); + T = deduceOpenCLPointeeAddrSpace(T); // Handle restrict on references. if (LValueRef) @@ -2862,7 +2862,7 @@ return QualType(); if (getLangOpts().OpenCL) - T = deduceOpenCLPointeeAddrSpace(*this, T); + T = deduceOpenCLPointeeAddrSpace(T); return Context.getBlockPointerType(T); } Index: clang/lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- clang/lib/Sema/SemaTemplateDeduction.cpp +++ clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3806,8 +3806,11 @@ // If P is a forwarding reference and the argument is an lvalue, the type // "lvalue reference to A" is used in place of A for type deduction. if (isForwardingReference(QualType(ParamRefType, 0), FirstInnerIndex) && - Arg->isLValue()) + Arg->isLValue()) { + if(S.getLangOpts().OpenCL) + ArgType = S.deduceOpenCLPointeeAddrSpace(ArgType); ArgType = S.Context.getLValueReferenceType(ArgType); + } } else { // C++ [temp.deduct.call]p2: // If P is not a reference type: Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -9364,6 +9364,7 @@ bool inferObjCARCLifetime(ValueDecl *decl); void deduceOpenCLAddressSpace(ValueDecl *decl); + QualType deduceOpenCLPointeeAddrSpace(QualType PointeeType); ExprResult HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits