Add support for language-specific address spaces.  On top of that,
add support for the OpenCL __private, __local, __constant and
__global address spaces, as well as the __read_only, _read_write and
__write_only image access specifiers.  Patch originally by ARM;
language-specific address space support by myself.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127915 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d20c258..fd5fd0e 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -190,6 +190,22 @@
   return 0;
 }
 
+static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T,
+                                             const LangOptions &LOpts) {
+  if (LOpts.FakeAddressSpaceMap) {
+    // The fake address space map must have a distinct entry for each
+    // language-specific address space.
+    static const unsigned FakeAddrSpaceMap[] = {
+      1, // opencl_global
+      2, // opencl_local
+      3  // opencl_constant
+    };
+    return FakeAddrSpaceMap;
+  } else {
+    return T.getAddressSpaceMap();
+  }
+}
+
 ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
                        const TargetInfo &t,
                        IdentifierTable &idents, SelectorTable &sels,
@@ -204,7 +220,8 @@
   sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
   cudaConfigureCallDecl(0),
   NullTypeSourceInfo(QualType()),
-  SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), Target(t),
+  SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)),
+  AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t),
   Idents(idents), Selectors(sels),
   BuiltinInfo(builtins),
   DeclarationNames(*this),
@@ -806,7 +823,8 @@
     Align = Target.getPointerAlign(0);
     break;
   case Type::BlockPointer: {
-    unsigned AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace();
+    unsigned AS = getTargetAddressSpace(
+        cast<BlockPointerType>(T)->getPointeeType());
     Width = Target.getPointerWidth(AS);
     Align = Target.getPointerAlign(AS);
     break;
@@ -815,13 +833,14 @@
   case Type::RValueReference: {
     // alignof and sizeof should never enter this code path here, so we go
     // the pointer route.
-    unsigned AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace();
+    unsigned AS = getTargetAddressSpace(
+        cast<ReferenceType>(T)->getPointeeType());
     Width = Target.getPointerWidth(AS);
     Align = Target.getPointerAlign(AS);
     break;
   }
   case Type::Pointer: {
-    unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
+    unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType());
     Width = Target.getPointerWidth(AS);
     Align = Target.getPointerAlign(AS);
     break;
@@ -1468,7 +1487,7 @@
   // the target.
   llvm::APInt ArySize(ArySizeIn);
   ArySize =
-    ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
+    ArySize.zextOrTrunc(Target.getPointerWidth(getTargetAddressSpace(EltTy)));
 
   llvm::FoldingSetNodeID ID;
   ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index a9eeb8b..1696cae 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/LangOptions.h"
 #include "llvm/ADT/APFloat.h"
@@ -19,6 +20,8 @@
 #include <cstdlib>
 using namespace clang;
 
+static const LangAS::Map DefaultAddrSpaceMap = { 0 };
+
 // TargetInfo Constructor.
 TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
   // Set defaults.  Defaults are set for a 32-bit RISC platform, like PPC or
@@ -64,6 +67,9 @@
 
   // Default to using the Itanium ABI.
   CXXABI = CXXABI_Itanium;
+
+  // Default to an empty address space map.
+  AddrSpaceMap = &DefaultAddrSpaceMap;
 }
 
 // Out of line virtual dtor for TargetInfo.
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 15ab6b0..7a1600f 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -627,7 +627,8 @@
     assert(!RetAI.getIndirectAlign() && "Align unused on indirect return.");
     ResultType = llvm::Type::getVoidTy(getLLVMContext());
     const llvm::Type *STy = ConvertType(RetTy, IsRecursive);
-    ArgTys.push_back(llvm::PointerType::get(STy, RetTy.getAddressSpace()));
+    unsigned AS = Context.getTargetAddressSpace(RetTy);
+    ArgTys.push_back(llvm::PointerType::get(STy, AS));
     break;
   }
 
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index b23b392..bf5e7a5 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -462,8 +462,8 @@
   // Bit size, align and offset of the type.
   // Size is always the size of a pointer. We can't use getTypeSize here
   // because that does not return the correct value for references.
-  uint64_t Size = 
-    CGM.getContext().Target.getPointerWidth(PointeeTy.getAddressSpace());
+  unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
+  uint64_t Size = CGM.getContext().Target.getPointerWidth(AS);
   uint64_t Align = CGM.getContext().getTypeAlign(Ty);
 
   return 
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 2cd4c87..7928656 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -179,7 +179,8 @@
     new llvm::GlobalVariable(CGM.getModule(), LTy,
                              Ty.isConstant(getContext()), Linkage,
                              CGM.EmitNullConstant(D.getType()), Name, 0,
-                             D.isThreadSpecified(), Ty.getAddressSpace());
+                             D.isThreadSpecified(),
+                             CGM.getContext().getTargetAddressSpace(Ty));
   GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
   if (Linkage != llvm::GlobalValue::InternalLinkage)
     GV->setVisibility(CurFn->getVisibility());
@@ -222,7 +223,7 @@
                                   OldGV->getLinkage(), Init, "",
                                   /*InsertBefore*/ OldGV,
                                   D.isThreadSpecified(),
-                                  D.getType().getAddressSpace());
+                           CGM.getContext().getTargetAddressSpace(D.getType()));
     GV->setVisibility(OldGV->getVisibility());
     
     // Steal the name of the old global
@@ -289,7 +290,8 @@
   // FIXME: It is really dangerous to store this in the map; if anyone
   // RAUW's the GV uses of this constant will be invalid.
   const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType());
-  const llvm::Type *LPtrTy = LTy->getPointerTo(D.getType().getAddressSpace());
+  const llvm::Type *LPtrTy =
+    LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType()));
   DMEntry = llvm::ConstantExpr::getBitCast(GV, LPtrTy);
 
   // Emit global variable debug descriptor for static vars.
@@ -724,7 +726,8 @@
 
     // Get the element type.
     const llvm::Type *LElemTy = ConvertTypeForMem(Ty);
-    const llvm::Type *LElemPtrTy = LElemTy->getPointerTo(Ty.getAddressSpace());
+    const llvm::Type *LElemPtrTy =
+      LElemTy->getPointerTo(CGM.getContext().getTargetAddressSpace(Ty));
 
     llvm::Value *VLASize = EmitVLASize(Ty);
 
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 99ea773..34a231c 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -726,7 +726,7 @@
     // Cast to the access type.
     const llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(),
                                                      AI.AccessWidth,
-                                                    ExprType.getAddressSpace());
+                              CGM.getContext().getTargetAddressSpace(ExprType));
     Ptr = Builder.CreateBitCast(Ptr, PTy);
 
     // Perform the load.
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index a735c3f..11b08c0 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -800,7 +800,7 @@
                                      E->getType().isConstant(CGM.getContext()),
                                      llvm::GlobalValue::InternalLinkage,
                                      C, ".compoundliteral", 0, false,
-                                     E->getType().getAddressSpace());
+                          CGM.getContext().getTargetAddressSpace(E->getType()));
       return C;
     }
     case Expr::DeclRefExprClass: {
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 11e8587..ea74abf 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1060,7 +1060,7 @@
     Ty = getTypes().ConvertTypeForMem(ASTTy);
 
   const llvm::PointerType *PTy =
-    llvm::PointerType::get(Ty, ASTTy.getAddressSpace());
+    llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy));
 
   llvm::StringRef MangledName = getMangledName(D);
   return GetOrCreateLLVMGlobal(MangledName, PTy, D);
@@ -1239,7 +1239,8 @@
   // from the type of the global (this happens with unions).
   if (GV == 0 ||
       GV->getType()->getElementType() != InitType ||
-      GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) {
+      GV->getType()->getAddressSpace() !=
+        getContext().getTargetAddressSpace(ASTTy)) {
 
     // Move the old entry aside so that we'll create a new one.
     Entry->setName(llvm::StringRef());
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 5254922..b9acbc4 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -270,14 +270,16 @@
     QualType ETy = RTy.getPointeeType();
     llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
     PointersToResolve.push_back(std::make_pair(ETy, PointeeType));
-    return llvm::PointerType::get(PointeeType, ETy.getAddressSpace());
+    unsigned AS = Context.getTargetAddressSpace(ETy);
+    return llvm::PointerType::get(PointeeType, AS);
   }
   case Type::Pointer: {
     const PointerType &PTy = cast<PointerType>(Ty);
     QualType ETy = PTy.getPointeeType();
     llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
     PointersToResolve.push_back(std::make_pair(ETy, PointeeType));
-    return llvm::PointerType::get(PointeeType, ETy.getAddressSpace());
+    unsigned AS = Context.getTargetAddressSpace(ETy);
+    return llvm::PointerType::get(PointeeType, AS);
   }
 
   case Type::VariableArray: {
@@ -402,7 +404,8 @@
     const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType();
     llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext());
     PointersToResolve.push_back(std::make_pair(FTy, PointeeType));
-    return llvm::PointerType::get(PointeeType, FTy.getAddressSpace());
+    unsigned AS = Context.getTargetAddressSpace(FTy);
+    return llvm::PointerType::get(PointeeType, AS);
   }
 
   case Type::MemberPointer: {
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 9d9c996..2b5c289 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -672,6 +672,8 @@
     Res.push_back("-fconstant-string-class");
     Res.push_back(Opts.ObjCConstantStringClass);
   }
+  if (Opts.FakeAddressSpaceMap)
+    Res.push_back("-ffake-address-space-map");
 }
 
 static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
@@ -1483,6 +1485,7 @@
   Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math);
   Opts.OptimizeSize = 0;
   Opts.MRTD = Args.hasArg(OPT_mrtd);
+  Opts.FakeAddressSpaceMap = Args.hasArg(OPT_ffake_address_space_map);
 
   // FIXME: Eliminate this dependency.
   unsigned Opt = getOptimizationLevel(Args, IK, Diags);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 4208380..f27ff79 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Basic/OpenCL.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/PrettyDeclStackTrace.h"
@@ -311,6 +312,56 @@
   }
 }
 
+void Parser::ParseOpenCLQualifiers(DeclSpec &DS) {
+  SourceLocation Loc = Tok.getLocation();
+  switch(Tok.getKind()) {
+    // OpenCL qualifiers:
+    case tok::kw___private:
+    case tok::kw_private: 
+      DS.addAttributes(AttrFactory.CreateIntegerAttribute( 
+          Actions.getASTContext(), 
+          PP.getIdentifierInfo("address_space"), Loc, 0));
+      break;
+      
+    case tok::kw___global:
+      DS.addAttributes(AttrFactory.CreateIntegerAttribute(
+          Actions.getASTContext(),
+          PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_global));
+      break;
+      
+    case tok::kw___local:
+      DS.addAttributes(AttrFactory.CreateIntegerAttribute(
+          Actions.getASTContext(),
+          PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_local));
+      break;
+      
+    case tok::kw___constant:
+      DS.addAttributes(AttrFactory.CreateIntegerAttribute(
+          Actions.getASTContext(),
+          PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_constant));
+      break;
+      
+    case tok::kw___read_only:
+      DS.addAttributes(AttrFactory.CreateIntegerAttribute(
+          Actions.getASTContext(), 
+          PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only));
+      break;
+      
+    case tok::kw___write_only:
+      DS.addAttributes(AttrFactory.CreateIntegerAttribute(
+          Actions.getASTContext(), 
+          PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only));
+      break;
+      
+    case tok::kw___read_write:
+      DS.addAttributes(AttrFactory.CreateIntegerAttribute(
+          Actions.getASTContext(),
+          PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_write));
+      break;
+    default: break;
+  }
+}
+
 void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
   Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
     << attrs.Range;
@@ -1446,6 +1497,20 @@
       ParseDecltypeSpecifier(DS);
       continue;
 
+    // OpenCL qualifiers:
+    case tok::kw_private: 
+      if (!getLang().OpenCL)
+        goto DoneWithDeclSpec;
+    case tok::kw___private:
+    case tok::kw___global:
+    case tok::kw___local:
+    case tok::kw___constant:
+    case tok::kw___read_only:
+    case tok::kw___write_only:
+    case tok::kw___read_write:
+      ParseOpenCLQualifiers(DS);
+      break;
+      
     case tok::less:
       // GCC ObjC supports types like "<SomeProtocol>" as a synonym for
       // "id<SomeProtocol>".  This is hopelessly old fashioned and dangerous,
@@ -1697,6 +1762,20 @@
     ParseDecltypeSpecifier(DS);
     return true;
 
+  // OpenCL qualifiers:
+  case tok::kw_private: 
+    if (!getLang().OpenCL)
+      return false;
+  case tok::kw___private:
+  case tok::kw___global:
+  case tok::kw___local:
+  case tok::kw___constant:
+  case tok::kw___read_only:
+  case tok::kw___write_only:
+  case tok::kw___read_write:
+    ParseOpenCLQualifiers(DS);
+    break;
+
   // C++0x auto support.
   case tok::kw_auto:
     if (!getLang().CPlusPlus0x)
@@ -2269,10 +2348,22 @@
 bool Parser::isTypeQualifier() const {
   switch (Tok.getKind()) {
   default: return false;
+
+    // type-qualifier only in OpenCL
+  case tok::kw_private:
+    return getLang().OpenCL;
+
     // type-qualifier
   case tok::kw_const:
   case tok::kw_volatile:
   case tok::kw_restrict:
+  case tok::kw___private:
+  case tok::kw___local:
+  case tok::kw___global:
+  case tok::kw___constant:
+  case tok::kw___read_only:
+  case tok::kw___read_write:
+  case tok::kw___write_only:
     return true;
   }
 }
@@ -2400,7 +2491,19 @@
   case tok::kw___w64:
   case tok::kw___ptr64:
   case tok::kw___pascal:
+
+  case tok::kw___private:
+  case tok::kw___local:
+  case tok::kw___global:
+  case tok::kw___constant:
+  case tok::kw___read_only:
+  case tok::kw___read_write:
+  case tok::kw___write_only:
+
     return true;
+
+  case tok::kw_private:
+    return getLang().OpenCL;
   }
 }
 
@@ -2413,6 +2516,9 @@
   switch (Tok.getKind()) {
   default: return false;
 
+  case tok::kw_private:
+    return getLang().OpenCL;
+
   case tok::identifier:   // foo::bar
     // Unfortunate hack to support "Class.factoryMethod" notation.
     if (getLang().ObjC1 && NextToken().is(tok::period))
@@ -2522,6 +2628,15 @@
   case tok::kw___ptr64:
   case tok::kw___forceinline:
   case tok::kw___pascal:
+
+  case tok::kw___private:
+  case tok::kw___local:
+  case tok::kw___global:
+  case tok::kw___constant:
+  case tok::kw___read_only:
+  case tok::kw___read_write:
+  case tok::kw___write_only:
+
     return true;
   }
 }
@@ -2627,6 +2742,21 @@
       isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
                                  getLang());
       break;
+
+    // OpenCL qualifiers:
+    case tok::kw_private: 
+      if (!getLang().OpenCL)
+        goto DoneWithTypeQuals;
+    case tok::kw___private:
+    case tok::kw___global:
+    case tok::kw___local:
+    case tok::kw___constant:
+    case tok::kw___read_only:
+    case tok::kw___write_only:
+    case tok::kw___read_write:
+      ParseOpenCLQualifiers(DS);
+      break;
+
     case tok::kw___w64:
     case tok::kw___ptr64:
     case tok::kw___cdecl:
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 1663fd5..a715989 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -94,6 +94,7 @@
     .Case("unavailable", AT_unavailable)
     .Case("overloadable", AT_overloadable)
     .Case("address_space", AT_address_space)
+    .Case("opencl_image_access", AT_opencl_image_access)
     .Case("always_inline", AT_always_inline)
     .Case("returns_twice", IgnoredAttribute)
     .Case("vec_type_hint", IgnoredAttribute)
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 5f6de14..3c11277 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2724,6 +2724,7 @@
   case AttributeList::AT_IBOutletCollection:
       HandleIBOutletCollection(D, Attr, S); break;
   case AttributeList::AT_address_space:
+  case AttributeList::AT_opencl_image_access:
   case AttributeList::AT_objc_gc:
   case AttributeList::AT_vector_size:
   case AttributeList::AT_neon_vector_type:
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index b78c21b..dc2d3ac 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
+#include "clang/Basic/OpenCL.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclObjC.h"
@@ -2965,6 +2966,41 @@
   return true;
 }
 
+/// Handle OpenCL image access qualifiers: read_only, write_only, read_write
+static void HandleOpenCLImageAccessAttribute(QualType& CurType,
+                                             const AttributeList &Attr,
+                                             Sema &S) {
+  // Check the attribute arguments.
+  if (Attr.getNumArgs() != 1) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+    Attr.setInvalid();
+    return;
+  }
+  Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
+  llvm::APSInt arg(32);
+  if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() ||
+      !sizeExpr->isIntegerConstantExpr(arg, S.Context)) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+      << "opencl_image_access" << sizeExpr->getSourceRange();
+    Attr.setInvalid();
+    return;
+  }
+  unsigned iarg = static_cast<unsigned>(arg.getZExtValue());
+  switch (iarg) {
+  case CLIA_read_only:
+  case CLIA_write_only:
+  case CLIA_read_write:
+    // Implemented in a separate patch
+    break;
+  default:
+    // Implemented in a separate patch
+    S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
+      << sizeExpr->getSourceRange();
+    Attr.setInvalid();
+    break;
+  }
+}
+
 /// HandleVectorSizeAttribute - this attribute is only applicable to integral
 /// and float scalars, although arrays, pointers, and function return values are
 /// allowed in conjunction with this construct. Aggregates with this attribute
@@ -3119,6 +3155,10 @@
                                "neon_polyvector_type");
       break;
 
+    case AttributeList::AT_opencl_image_access:
+      HandleOpenCLImageAccessAttribute(type, attr, state.getSema());
+      break;
+
     FUNCTION_TYPE_ATTRS_CASELIST:
       // Never process function type attributes as part of the
       // declaration-specifiers.