Add optional access to ptr<>

This also completes the work to resolve the access controls for each
storage type.

Fixed: tint:846
Change-Id: Iab24057ec14620a2978ec63c4a91ba12d1bc6e9b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/53381
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 14f4b7d..712e092 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -307,8 +307,12 @@
     }
     if (auto* t = ty->As<ast::Pointer>()) {
       if (auto* el = Type(t->type())) {
+        auto access = t->access();
+        if (access == ast::kUndefined) {
+          access = DefaultAccessForStorageClass(t->storage_class());
+        }
         return builder_->create<sem::Pointer>(const_cast<sem::Type*>(el),
-                                              t->storage_class());
+                                              t->storage_class(), access);
       }
       return nullptr;
     }
@@ -477,11 +481,17 @@
     }
   }
 
+  auto access = var->declared_access();
+  if (access == ast::Access::kUndefined) {
+    access = DefaultAccessForStorageClass(storage_class);
+  }
+
   auto* type = storage_type;
   if (!var->is_const()) {
     // Variable declaration. Unlike `let`, `var` has storage.
     // Variables are always of a reference type to the declared storage type.
-    type = builder_->create<sem::Reference>(storage_type, storage_class);
+    type =
+        builder_->create<sem::Reference>(storage_type, storage_class, access);
   }
 
   if (rhs_type && !ValidateVariableConstructor(var, storage_type, type_name,
@@ -489,15 +499,6 @@
     return nullptr;
   }
 
-  auto access = var->declared_access();
-  if (access == ast::Access::kUndefined &&
-      storage_class == ast::StorageClass::kStorage) {
-    // https://gpuweb.github.io/gpuweb/wgsl/#access-mode-defaults
-    // For the storage storage class, the access mode is optional, and defaults
-    // to read.
-    access = ast::Access::kRead;
-  }
-
   auto* info = variable_infos_.Create(var, const_cast<sem::Type*>(type),
                                       type_name, storage_class, access);
   variable_to_info_.emplace(var, info);
@@ -505,6 +506,21 @@
   return info;
 }
 
+ast::AccessControl Resolver::DefaultAccessForStorageClass(
+    ast::StorageClass storage_class) {
+  // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
+  switch (storage_class) {
+    case ast::StorageClass::kStorage:
+      return ast::Access::kRead;
+    case ast::StorageClass::kUniform:
+    case ast::StorageClass::kUniformConstant:
+      return ast::Access::kRead;
+    default:
+      break;
+  }
+  return ast::Access::kReadWrite;
+}
+
 bool Resolver::ValidateVariableConstructor(const ast::Variable* var,
                                            const sem::Type* storage_type,
                                            const std::string& type_name,
@@ -1603,7 +1619,8 @@
 
   // If we're extracting from a reference, we return a reference.
   if (auto* ref = res->As<sem::Reference>()) {
-    ret = builder_->create<sem::Reference>(ret, ref->StorageClass());
+    ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
+                                           ref->Access());
   }
   SetType(expr, ret);
 
@@ -1959,7 +1976,8 @@
 
     // If we're extracting from a reference, we return a reference.
     if (auto* ref = structure->As<sem::Reference>()) {
-      ret = builder_->create<sem::Reference>(ret, ref->StorageClass());
+      ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
+                                             ref->Access());
     }
 
     builder_->Sem().Add(expr, builder_->create<sem::StructMemberAccess>(
@@ -2028,7 +2046,8 @@
       ret = vec->type();
       // If we're extracting from a reference, we return a reference.
       if (auto* ref = structure->As<sem::Reference>()) {
-        ret = builder_->create<sem::Reference>(ret, ref->StorageClass());
+        ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
+                                               ref->Access());
       }
     } else {
       // The vector will have a number of components equal to the length of
@@ -2291,8 +2310,8 @@
 
     case ast::UnaryOp::kAddressOf:
       if (auto* ref = expr_type->As<sem::Reference>()) {
-        type = builder_->create<sem::Pointer>(ref->StoreType(),
-                                              ref->StorageClass());
+        type = builder_->create<sem::Pointer>(
+            ref->StoreType(), ref->StorageClass(), ref->Access());
       } else {
         diagnostics_.add_error("cannot take the address of expression",
                                unary->expr()->source());
@@ -2302,8 +2321,8 @@
 
     case ast::UnaryOp::kIndirection:
       if (auto* ptr = expr_type->As<sem::Pointer>()) {
-        type = builder_->create<sem::Reference>(ptr->StoreType(),
-                                                ptr->StorageClass());
+        type = builder_->create<sem::Reference>(
+            ptr->StoreType(), ptr->StorageClass(), ptr->Access());
       } else {
         diagnostics_.add_error("cannot dereference expression of type '" +
                                    TypeNameOf(unary->expr()) + "'",