Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -2056,6 +2056,8 @@ bool isAlignValT() const; // C++17 std::align_val_t bool isStdByteType() const; // C++17 std::byte bool isAtomicType() const; // C11 _Atomic() + bool isAutoType() const; // C++11 auto or + // C++14 decltype(auto) #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ bool is##Id##Type() const; @@ -6502,6 +6504,10 @@ return isa(CanonicalType); } +inline bool Type::isAutoType() const { + return isa(CanonicalType); +} + inline bool Type::isObjCQualifiedIdType() const { if (const auto *OPT = getAs()) return OPT->isObjCQualifiedIdType(); Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -7398,6 +7398,17 @@ bool IsFuncType = ChunkIndex < D.getNumTypeObjects() && D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function; + bool IsAutoPointee = false; + if (State.getSema().getLangOpts().OpenCLCPlusPlus){ + // Detect if pointer or reference are part of auto type. + if (T->isPointerType() || T->isReferenceType()) { + auto Pointee = T->getPointeeType(); + do { + IsAutoPointee = Pointee->isAutoType(); + Pointee = Pointee->getPointeeType(); + } while (!Pointee.isNull()); + } + } if ( // Do not deduce addr space for function return type and function type, // otherwise it will fail some sema check. IsFuncReturnType || IsFuncType || @@ -7425,6 +7436,9 @@ // Do not deduce addr space of decltype because it will be taken from // its argument. T->isDecltypeType() || + // Do not deduce addr space for auto pointee type because it is taken from + // the initializing expression type during the type deduction. + (T->isAutoType() && IsPointee) || (IsAutoPointee) || // OpenCL spec v2.0 s6.9.b: // The sampler type cannot be used with the __local and __global address // space qualifiers. Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -4538,8 +4538,17 @@ /// Helper to deduce addr space of a pointee type in OpenCL mode. /// If the type is updated it will be overwritten in PointeeType param. -static void deduceOpenCLPointeeAddrSpace(Sema &SemaRef, QualType &PointeeType) { - if (PointeeType.getAddressSpace() == LangAS::Default) +static void deduceOpenCLPointeeAddrSpace(Sema &SemaRef, QualType &PointeeType, + QualType TLT) { + // Prevent deducing addr space for auto because it will be taken from + // the initializing expression. + bool IsAuto = false; + auto Pointee = TLT->getPointeeType(); + do { + IsAuto = Pointee->isAutoType(); + Pointee = Pointee->getPointeeType(); + } while (!Pointee.isNull()); + if (!IsAuto && PointeeType.getAddressSpace() == LangAS::Default) PointeeType = SemaRef.Context.getAddrSpaceQualType(PointeeType, LangAS::opencl_generic); } @@ -4553,7 +4562,7 @@ return QualType(); if (SemaRef.getLangOpts().OpenCL) - deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType); + deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType, TL.getType()); QualType Result = TL.getType(); if (PointeeType->getAs()) { @@ -4594,7 +4603,7 @@ return QualType(); if (SemaRef.getLangOpts().OpenCL) - deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType); + deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType, TL.getType()); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || @@ -4626,7 +4635,7 @@ return QualType(); if (SemaRef.getLangOpts().OpenCL) - deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType); + deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType, TL.getType()); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || Index: test/SemaOpenCLCXX/addrspace-auto.cl =================================================================== --- /dev/null +++ test/SemaOpenCLCXX/addrspace-auto.cl @@ -0,0 +1,31 @@ +//RUN: %clang_cc1 %s -cl-std=clc++ -pedantic -ast-dump -verify | FileCheck %s + +kernel void test(){ + int i; +//CHECK: VarDecl {{.*}} ai 'int':'int' + auto ai = i; + + constexpr int c = 1; +//CHECK: VarDecl {{.*}} used cai '__constant int':'__constant int' + __constant auto cai = c; +//CHECK: VarDecl {{.*}} aii 'int':'int' + auto aii = cai; + +//CHECK: VarDecl {{.*}} ref 'int &' + auto& ref = i; +//CHECK: VarDecl {{.*}} ptr 'int *' + auto* ptr = &i; +//CHECK: VarDecl {{.*}} ref_c '__constant int &' + auto& ref_c = cai; + +//CHECK: VarDecl {{.*}} ptrptr 'int **' + auto ** ptrptr = &ptr; +//CHECK: VarDecl {{.*}} refptr 'int *&' + auto *& refptr = ptr; + +//CHECK: VarDecl {{.*}} invalid gref '__global auto &' + __global auto& gref = i; //expected-error{{variable 'gref' with type '__global auto &' has incompatible initializer of type 'int'}} + __local int* ptr_l; +//CHECK: VarDecl {{.*}} invalid gptr '__global auto *' + __global auto* gptr = ptr_l; //expected-error{{variable 'gptr' with type '__global auto *' has incompatible initializer of type '__local int *'}} +}