pmatos updated this revision to Diff 491707.
pmatos added a comment.

Further tests for use of tables in conditional branches.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139010/new/

https://reviews.llvm.org/D139010

Files:
  clang/include/clang/AST/Expr.h
  clang/include/clang/AST/Stmt.h
  clang/include/clang/AST/Type.h
  clang/include/clang/Basic/BuiltinsWebAssembly.def
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/Specifiers.h
  clang/include/clang/Sema/Sema.h
  clang/include/clang/Serialization/ASTBitCodes.h
  clang/include/clang/Serialization/TypeBitCodes.def
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/AST/Type.cpp
  clang/lib/Basic/Targets/WebAssembly.cpp
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CGValue.h
  clang/lib/Sema/SemaCast.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CodeGen/WebAssembly/builtins-table.c
  clang/test/CodeGen/WebAssembly/table.c
  clang/test/Sema/builtins-wasm.c
  clang/test/Sema/wasm-refs.c
  clang/test/SemaCXX/wasm-refs-and-tables.cpp
  clang/test/SemaCXX/wasm-refs.cpp
  llvm/include/llvm/CodeGen/WasmAddressSpaces.h
  llvm/include/llvm/IR/Type.h
  llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
  llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
  llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
  llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp

Index: llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
+++ llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
@@ -62,8 +62,9 @@
   for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
     PtrToIntInst *PTI = dyn_cast<PtrToIntInst>(&*I);
     IntToPtrInst *ITP = dyn_cast<IntToPtrInst>(&*I);
-    if (!(PTI && WebAssembly::isRefType(PTI->getPointerOperand()->getType())) &&
-        !(ITP && WebAssembly::isRefType(ITP->getDestTy())))
+    if (!(PTI &&
+          PTI->getPointerOperand()->getType()->isWebAssemblyReferenceType()) &&
+        !(ITP && ITP->getDestTy()->isWebAssemblyReferenceType()))
       continue;
 
     UndefValue *U = UndefValue::get(I->getType());
Index: llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -1202,7 +1202,7 @@
   // Lastly, if this is a call to a funcref we need to add an instruction
   // table.set to the chain and transform the call.
   if (CLI.CB &&
-      WebAssembly::isFuncrefType(CLI.CB->getCalledOperand()->getType())) {
+      CLI.CB->getCalledOperand()->getType()->isWebAssemblyFuncrefType()) {
     // In the absence of function references proposal where a funcref call is
     // lowered to call_ref, using reference types we generate a table.set to set
     // the funcref to a special table used solely for this purpose, followed by
Index: llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
===================================================================
--- llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
+++ llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
@@ -45,43 +45,6 @@
   Multivalue = 0xffff,
 };
 
-enum WasmAddressSpace : unsigned {
-  // Default address space, for pointers to linear memory (stack, heap, data).
-  WASM_ADDRESS_SPACE_DEFAULT = 0,
-  // A non-integral address space for pointers to named objects outside of
-  // linear memory: WebAssembly globals or WebAssembly locals.  Loads and stores
-  // to these pointers are lowered to global.get / global.set or local.get /
-  // local.set, as appropriate.
-  WASM_ADDRESS_SPACE_VAR = 1,
-  // A non-integral address space for externref values
-  WASM_ADDRESS_SPACE_EXTERNREF = 10,
-  // A non-integral address space for funcref values
-  WASM_ADDRESS_SPACE_FUNCREF = 20,
-};
-
-inline bool isDefaultAddressSpace(unsigned AS) {
-  return AS == WASM_ADDRESS_SPACE_DEFAULT;
-}
-inline bool isWasmVarAddressSpace(unsigned AS) {
-  return AS == WASM_ADDRESS_SPACE_VAR;
-}
-inline bool isValidAddressSpace(unsigned AS) {
-  return isDefaultAddressSpace(AS) || isWasmVarAddressSpace(AS);
-}
-inline bool isFuncrefType(const Type *Ty) {
-  return isa<PointerType>(Ty) &&
-         Ty->getPointerAddressSpace() ==
-             WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF;
-}
-inline bool isExternrefType(const Type *Ty) {
-  return isa<PointerType>(Ty) &&
-         Ty->getPointerAddressSpace() ==
-             WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF;
-}
-inline bool isRefType(const Type *Ty) {
-  return isFuncrefType(Ty) || isExternrefType(Ty);
-}
-
 inline bool isRefType(wasm::ValType Type) {
   return Type == wasm::ValType::EXTERNREF || Type == wasm::ValType::FUNCREF;
 }
Index: llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
+++ llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
@@ -184,12 +184,12 @@
   wasm::ValType ValTy;
   bool IsTable = false;
   if (GlobalVT->isArrayTy() &&
-      WebAssembly::isRefType(GlobalVT->getArrayElementType())) {
+      GlobalVT->getArrayElementType()->isWebAssemblyReferenceType()) {
     IsTable = true;
     const Type *ElTy = GlobalVT->getArrayElementType();
-    if (WebAssembly::isExternrefType(ElTy))
+    if (ElTy->isWebAssemblyExternrefType())
       ValTy = wasm::ValType::EXTERNREF;
-    else if (WebAssembly::isFuncrefType(ElTy))
+    else if (ElTy->isWebAssemblyFuncrefType())
       ValTy = wasm::ValType::FUNCREF;
     else
       report_fatal_error("unhandled reference type");
Index: llvm/include/llvm/IR/Type.h
===================================================================
--- llvm/include/llvm/IR/Type.h
+++ llvm/include/llvm/IR/Type.h
@@ -20,6 +20,7 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TypeSize.h"
+#include "llvm/CodeGen/WasmAddressSpaces.h"
 #include <cassert>
 #include <cstdint>
 #include <iterator>
@@ -206,6 +207,21 @@
   /// Return true if this is a target extension type.
   bool isTargetExtTy() const { return getTypeID() == TargetExtTyID; }
 
+  /// Return true if this is a WebAssembly Reference Type.
+  bool isWebAssemblyReferenceType() const { return isWebAssemblyExternrefType() || isWebAssemblyFuncrefType(); }
+
+  /// Return true if this is a WebAssembly Externref Type.
+  bool isWebAssemblyExternrefType() const {
+    return getPointerAddressSpace() ==
+             WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF;
+  }
+
+  /// Return true if this is a WebAssembly Funcref Type.
+  bool isWebAssemblyFuncrefType() const {
+    return getPointerAddressSpace() ==
+             WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF;
+  }
+
   /// Return true if this is a FP type or a vector of FP.
   bool isFPOrFPVectorTy() const { return getScalarType()->isFloatingPointTy(); }
 
Index: llvm/include/llvm/CodeGen/WasmAddressSpaces.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/CodeGen/WasmAddressSpaces.h
@@ -0,0 +1,43 @@
+//===--- llvm/CodeGen/WasmAddressSpaces.h -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Address Spaces for WebAssembly Type Handling
+//
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+
+namespace WebAssembly {
+
+enum WasmAddressSpace : unsigned {
+  // Default address space, for pointers to linear memory (stack, heap, data).
+  WASM_ADDRESS_SPACE_DEFAULT = 0,
+  // A non-integral address space for pointers to named objects outside of
+  // linear memory: WebAssembly globals or WebAssembly locals.  Loads and stores
+  // to these pointers are lowered to global.get / global.set or local.get /
+  // local.set, as appropriate.
+  WASM_ADDRESS_SPACE_VAR = 1,
+  // A non-integral address space for externref values
+  WASM_ADDRESS_SPACE_EXTERNREF = 10,
+  // A non-integral address space for funcref values
+  WASM_ADDRESS_SPACE_FUNCREF = 20,
+};
+
+inline bool isDefaultAddressSpace(unsigned AS) {
+  return AS == WASM_ADDRESS_SPACE_DEFAULT;
+}
+inline bool isWasmVarAddressSpace(unsigned AS) {
+  return AS == WASM_ADDRESS_SPACE_VAR;
+}
+inline bool isValidAddressSpace(unsigned AS) {
+  return isDefaultAddressSpace(AS) || isWasmVarAddressSpace(AS);
+}
+
+} // namespace WebAssembly
+
+} // namespace llvm
\ No newline at end of file
Index: clang/test/SemaCXX/wasm-refs.cpp
===================================================================
--- clang/test/SemaCXX/wasm-refs.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -std=gnu++11 -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
-
-// This file tests C++ specific constructs with WebAssembly references and
-// tables. See wasm-refs-and-tables.c for C constructs.
-
-__externref_t ref;
-__externref_t &ref_ref1 = ref; // expected-error {{reference to WebAssembly reference type is not allowed}}
-__externref_t &ref_ref2(ref);  // expected-error {{reference to WebAssembly reference type is not allowed}}
-
-static __externref_t table[0];                    // expected-error {{array has sizeless element type '__externref_t'}}
-static __externref_t (&ref_to_table1)[0] = table; // expected-error {{array has sizeless element type '__externref_t'}}
-static __externref_t (&ref_to_table2)[0](table);  // expected-error {{array has sizeless element type '__externref_t'}}
-
-void illegal_argument_1(__externref_t &r); // expected-error {{reference to WebAssembly reference type is not allowed}}
-void illegal_argument_2(__externref_t (&t)[0]); // expected-error {{array has sizeless element type '__externref_t'}}
-
-__externref_t &illegal_return_1(); // expected-error {{reference to WebAssembly reference type is not allowed}}
-__externref_t (&illegal_return_2())[0]; // expected-error {{array has sizeless element type '__externref_t'}}
-
-void illegal_throw1() throw(__externref_t);   // expected-error {{sizeless type '__externref_t' is not allowed in exception specification}}
-void illegal_throw2() throw(__externref_t *); // expected-error {{pointer to WebAssembly reference type is not allowed}}
-void illegal_throw3() throw(__externref_t &); // expected-error {{reference to WebAssembly reference type is not allowed}}
-void illegal_throw4() throw(__externref_t[0]); // expected-error {{array has sizeless element type '__externref_t'}}
-
-class RefClass {
-  __externref_t f1;       // expected-error {{field has sizeless type '__externref_t'}}
-  __externref_t f2[0];    // expected-error {{array has sizeless element type '__externref_t'}}
-  __externref_t f3[];     // expected-error {{array has sizeless element type '__externref_t'}}
-  __externref_t f4[0][0]; // expected-error {{array has sizeless element type '__externref_t'}}
-  __externref_t *f5;      // expected-error {{pointer to WebAssembly reference type is not allowed}}
-  __externref_t ****f6;   // expected-error {{pointer to WebAssembly reference type is not allowed}}
-  __externref_t (*f7)[0]; // expected-error {{array has sizeless element type '__externref_t'}}
-};
-
-struct AStruct {};
-
-template <typename T>
-struct TemplatedStruct {
-  T f; // expected-error {{field has sizeless type '__externref_t'}}
-  void foo(T);
-  T bar(void);
-  T arr[0]; // expected-error {{array has sizeless element type '__externref_t'}}
-  T *ptr;   // expected-error {{pointer to WebAssembly reference type is not allowed}}
-};
-
-void func() {
-  int foo = 40;
-  static_cast<__externref_t>(foo);      // expected-error {{static_cast from 'int' to '__externref_t' is not allowed}}
-  static_cast<__externref_t *>(&foo);   // expected-error {{pointer to WebAssembly reference type is not allowed}}
-  static_cast<int>(ref);                // expected-error {{static_cast from '__externref_t' to 'int' is not allowed}}
-  __externref_t(10);                    // expected-error {{functional-style cast from 'int' to '__externref_t' is not allowed}}
-  int i(ref);                           // expected-error {{cannot initialize a variable of type 'int' with an lvalue of type '__externref_t'}}
-  const_cast<__externref_t[0]>(table);  // expected-error {{array has sizeless element type '__externref_t'}}
-  const_cast<__externref_t *>(table);   // expected-error {{pointer to WebAssembly reference type is not allowed}}
-  reinterpret_cast<__externref_t>(foo); // expected-error {{reinterpret_cast from 'int' to '__externref_t' is not allowed}}
-  reinterpret_cast<int>(ref);           // expected-error {{reinterpret_cast from '__externref_t' to 'int' is not allowed}}
-  int iarr[0];
-  reinterpret_cast<__externref_t[0]>(iarr); // expected-error {{array has sizeless element type '__externref_t'}}
-  reinterpret_cast<__externref_t *>(iarr);  // expected-error {{pointer to WebAssembly reference type is not allowed}}
-  dynamic_cast<__externref_t>(foo);         // expected-error {{invalid target type '__externref_t' for dynamic_cast; target type must be a reference or pointer type to a defined class}}
-  dynamic_cast<__externref_t *>(&foo);      // expected-error {{pointer to WebAssembly reference type is not allowed}}
-
-  TemplatedStruct<__externref_t> ts1;    // expected-note {{in instantiation}}
-  TemplatedStruct<__externref_t *> ts2;  // expected-error {{pointer to WebAssembly reference type is not allowed}}
-  TemplatedStruct<__externref_t &> ts3;  // expected-error {{reference to WebAssembly reference type is not allowed}}
-  TemplatedStruct<__externref_t[0]> ts4; // expected-error {{array has sizeless element type '__externref_t'}}
-
-  auto auto_ref = ref;
-
-  auto fn1 = [](__externref_t x) { return x; };
-  auto fn2 = [](__externref_t *x) { return x; };   // expected-error {{pointer to WebAssembly reference type is not allowed}}
-  auto fn3 = [](__externref_t &x) { return x; };   // expected-error {{reference to WebAssembly reference type is not allowed}}
-  auto fn4 = [](__externref_t x[0]) { return x; }; // expected-error {{array has sizeless element type '__externref_t'}}
-  auto fn5 = [&auto_ref](void) { return true; };   // expected-error {{cannot capture WebAssembly reference}}
-  auto fn6 = [auto_ref](void) { return true; };    // expected-error {{cannot capture WebAssembly reference}}
-  auto fn7 = [&](void) { auto_ref; return true; };                        // expected-error {{cannot capture WebAssembly reference}}
-  auto fn8 = [=](void) { auto_ref; return true; };                        // expected-error {{cannot capture WebAssembly reference}}
-
-  alignof(__externref_t);    // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
-  alignof(ref);              // expected-warning {{'alignof' applied to an expression is a GNU extension}} expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
-  alignof(__externref_t[0]); // expected-error {{array has sizeless element type '__externref_t'}}
-
-  throw ref;  // expected-error {{cannot throw object of sizeless type '__externref_t'}}
-  throw &ref; // expected-error {{cannot take address of WebAssembly reference}}
-
-  try {
-  } catch (__externref_t) { // expected-error {{cannot catch sizeless type '__externref_t'}}
-  }
-  try {
-  } catch (__externref_t *) { // expected-error {{pointer to WebAssembly reference type is not allowed}}
-  }
-  try {
-  } catch (__externref_t &) { // expected-error {{reference to WebAssembly reference type is not allowed}}
-  }
-  try {
-  } catch (__externref_t[0]) { // expected-error {{array has sizeless element type '__externref_t'}}
-  }
-
-  new __externref_t;    // expected-error {{allocation of sizeless type '__externref_t'}}
-  new __externref_t[0]; // expected-error {{allocation of sizeless type '__externref_t'}}
-
-  delete ref;     // expected-error {{cannot delete expression of type '__externref_t'}}
-}
Index: clang/test/SemaCXX/wasm-refs-and-tables.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/wasm-refs-and-tables.cpp
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
+
+// Note: As WebAssembly references are sizeless types, we don't exhaustively
+// test for cases covered by sizeless-1.c and similar tests.
+
+// Unlike standard sizeless types, reftype globals are supported.
+__externref_t r1;
+extern __externref_t r2;
+static __externref_t r3;
+
+__externref_t *t1;               // expected-error {{pointer to WebAssembly reference type is not allowed}}
+__externref_t **t2;              // expected-error {{pointer to WebAssembly reference type is not allowed}}
+__externref_t ******t3;          // expected-error {{pointer to WebAssembly reference type is not allowed}}
+static __externref_t t4[3];      // expected-error {{only zero-length WebAssembly tables are currently supported}}
+static __externref_t t5[];       // expected-error {{only zero-length WebAssembly tables are currently supported}}
+static __externref_t t6[] = {0}; // expected-error {{only zero-length WebAssembly tables are currently supported}}
+__externref_t t7[0];             // expected-error {{WebAssembly table must be static}}
+static __externref_t t8[0][0];   // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+static __externref_t (*t9)[0];   // expected-error {{cannot form a pointer to a WebAssembly table}}
+
+static __externref_t table[0];
+static __externref_t other_table[0] = {};
+
+struct s {
+  __externref_t f1;       // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f2[0];    // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f3[];     // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+  __externref_t *f5;      // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  __externref_t ****f6;   // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
+};
+
+union u {
+  __externref_t f1;       // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f2[0];    // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f3[];     // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+  __externref_t *f5;      // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  __externref_t ****f6;   // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
+};
+
+void illegal_argument_1(__externref_t table[]);     // expected-error {{cannot use WebAssembly table as a function parameter}}
+void illegal_argument_2(__externref_t table[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+void illegal_argument_3(__externref_t *table);      // expected-error {{pointer to WebAssembly reference type is not allowed}}
+void illegal_argument_4(__externref_t ***table);    // expected-error {{pointer to WebAssembly reference type is not allowed}}
+void illegal_argument_5(__externref_t (*table)[0]); // expected-error {{cannot form a pointer to a WebAssembly table}}
+
+__externref_t *illegal_return_1();   // expected-error {{pointer to WebAssembly reference type is not allowed}}
+__externref_t ***illegal_return_2(); // expected-error {{pointer to WebAssembly reference type is not allowed}}
+__externref_t (*illegal_return_3())[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
+
+void varargs(int, ...);
+
+__externref_t func(__externref_t ref) {
+  &ref; // expected-error {{cannot take address of WebAssembly reference}}
+  int foo = 40;
+  (__externref_t *)(&foo);     // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  (__externref_t ****)(&foo);  // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  sizeof(ref);                 // expected-error {{invalid application of 'sizeof' to sizeless type '__externref_t'}}
+  sizeof(__externref_t);       // expected-error {{invalid application of 'sizeof' to sizeless type '__externref_t'}}
+  sizeof(__externref_t[0]);    // expected-error {{invalid application of 'sizeof' to WebAssembly table}}
+  sizeof(table);               // expected-error {{invalid application of 'sizeof' to WebAssembly table}}
+  sizeof(__externref_t[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+  sizeof(__externref_t *);     // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  sizeof(__externref_t ***);   // expected-error {{pointer to WebAssembly reference type is not allowed}};
+  // expected-warning@+1 {{'_Alignof' applied to an expression is a GNU extension}}
+  _Alignof(ref);                 // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
+  _Alignof(__externref_t);       // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
+  _Alignof(__externref_t[]);     // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
+  _Alignof(__externref_t[0]);    // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
+  _Alignof(table);               // expected-warning {{'_Alignof' applied to an expression is a GNU extension}} expected-error {{invalid application of 'alignof' to WebAssembly table}}
+  _Alignof(__externref_t[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+  _Alignof(__externref_t *);     // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  _Alignof(__externref_t ***);   // expected-error {{pointer to WebAssembly reference type is not allowed}};
+  varargs(1, ref);               // expected-error {{cannot pass expression of type '__externref_t' to variadic function}}
+
+  __externref_t lt1[0];           // expected-error {{WebAssembly table cannot be declared within a function}}
+  static __externref_t lt2[0];    // expected-error {{WebAssembly table cannot be declared within a function}}
+  static __externref_t lt3[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+  static __externref_t(*lt4)[0];  // expected-error {{cannot form a pointer to a WebAssembly table}}
+  illegal_argument_1(table);      // expected-error {{no matching function for call to 'illegal_argument_1'}}
+  varargs(1, table);              // expected-error {{cannot use WebAssembly table as a function parameter}}
+  table == 1;                     // expected-error {{invalid operands to binary expression ('__attribute__((address_space(1))) __externref_t[0]' and 'int')}}
+  1 >= table;                     // expected-error {{invalid operands to binary expression ('int' and '__attribute__((address_space(1))) __externref_t[0]')}}
+  !table;                         // expected-error {{invalid argument type '__attribute__((address_space(1))) __externref_t *' to unary expression}}
+  1 && table;                     // expected-error {{invalid operands to binary expression ('int' and '__attribute__((address_space(1))) __externref_t[0]')}}
+  table || 1;                     // expected-error {{invalid operands to binary expression ('__attribute__((address_space(1))) __externref_t[0]' and 'int')}}
+  1 ? table : table;              // expected-error {{cannot use a WebAssembly table within a branch of a conditional expression}}
+  (void *)table;                  // expected-error {{cannot cast from a WebAssembly table}}
+  void *u;
+  u = table;       // expected-error {{cannot assign a WebAssembly table}}
+  void *v = table; // expected-error {{cannot assign a WebAssembly table}}
+  &table;          // expected-error {{cannot form a reference to a WebAssembly table}}
+  foo ? table : other_table; // expected-error {{cannot use a WebAssembly table within a branch of a conditional expression}}
+  table ? : other_table; // expected-error {{cannot use a WebAssembly table within a branch of a conditional expression}}
+  
+  table[0];
+  table[0] = ref;
+  return ref;
+}
+
+void *ret_void_ptr() {
+  return table; // expected-error {{cannot return a WebAssembly table}}
+}
Index: clang/test/Sema/wasm-refs.c
===================================================================
--- clang/test/Sema/wasm-refs.c
+++ clang/test/Sema/wasm-refs.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-feature +reference-types %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
 
 // Note: As WebAssembly references are sizeless types, we don't exhaustively
 // test for cases covered by sizeless-1.c and similar tests.
@@ -11,39 +11,45 @@
 __externref_t *t1;               // expected-error {{pointer to WebAssembly reference type is not allowed}}
 __externref_t **t2;              // expected-error {{pointer to WebAssembly reference type is not allowed}}
 __externref_t ******t3;          // expected-error {{pointer to WebAssembly reference type is not allowed}}
-static __externref_t t4[3];      // expected-error {{array has sizeless element type '__externref_t'}}
-static __externref_t t5[];       // expected-error {{array has sizeless element type '__externref_t'}}
-static __externref_t t6[] = {0}; // expected-error {{array has sizeless element type '__externref_t'}}
-__externref_t t7[0];             // expected-error {{array has sizeless element type '__externref_t'}}
-static __externref_t t8[0][0];   // expected-error {{array has sizeless element type '__externref_t'}}
+static __externref_t t4[3];      // expected-error {{only zero-length WebAssembly tables are currently supported}}
+static __externref_t t5[];       // expected-error {{only zero-length WebAssembly tables are currently supported}}
+static __externref_t t6[] = {0}; // expected-error {{only zero-length WebAssembly tables are currently supported}}
+__externref_t t7[0];             // expected-error {{WebAssembly table must be static}}
+static __externref_t t8[0][0];   // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+static __externref_t (*t9)[0];   // expected-error {{cannot form a pointer to a WebAssembly table}}
 
-static __externref_t table[0]; // expected-error {{array has sizeless element type '__externref_t'}}
+static __externref_t table[0];
+static __externref_t other_table[0] = {};
 
 struct s {
   __externref_t f1;       // expected-error {{field has sizeless type '__externref_t'}}
-  __externref_t f2[0];    // expected-error {{array has sizeless element type '__externref_t'}}
-  __externref_t f3[];     // expected-error {{array has sizeless element type '__externref_t'}}
-  __externref_t f4[0][0]; // expected-error {{array has sizeless element type '__externref_t'}}
+  __externref_t f2[0];    // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f3[];     // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
   __externref_t *f5;      // expected-error {{pointer to WebAssembly reference type is not allowed}}
   __externref_t ****f6;   // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
 };
 
 union u {
   __externref_t f1;       // expected-error {{field has sizeless type '__externref_t'}}
-  __externref_t f2[0];    // expected-error {{array has sizeless element type '__externref_t'}}
-  __externref_t f3[];     // expected-error {{array has sizeless element type '__externref_t'}}
-  __externref_t f4[0][0]; // expected-error {{array has sizeless element type '__externref_t'}}
+  __externref_t f2[0];    // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f3[];     // expected-error {{field has sizeless type '__externref_t'}}
+  __externref_t f4[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
   __externref_t *f5;      // expected-error {{pointer to WebAssembly reference type is not allowed}}
   __externref_t ****f6;   // expected-error {{pointer to WebAssembly reference type is not allowed}}
+  __externref_t (*f7)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
 };
 
-void illegal_argument_1(__externref_t table[]);     // expected-error {{array has sizeless element type '__externref_t'}}
-void illegal_argument_2(__externref_t table[0][0]); // expected-error {{array has sizeless element type '__externref_t'}}
+void illegal_argument_1(__externref_t table[]);     // expected-error {{cannot use WebAssembly table as a function parameter}}
+void illegal_argument_2(__externref_t table[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
 void illegal_argument_3(__externref_t *table);      // expected-error {{pointer to WebAssembly reference type is not allowed}}
 void illegal_argument_4(__externref_t ***table);    // expected-error {{pointer to WebAssembly reference type is not allowed}}
+void illegal_argument_5(__externref_t (*table)[0]); // expected-error {{cannot form a pointer to a WebAssembly table}}
 
 __externref_t *illegal_return_1();   // expected-error {{pointer to WebAssembly reference type is not allowed}}
 __externref_t ***illegal_return_2(); // expected-error {{pointer to WebAssembly reference type is not allowed}}
+__externref_t (*illegal_return_3())[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
 
 void varargs(int, ...);
 
@@ -54,18 +60,47 @@
   (__externref_t ****)(&foo);  // expected-error {{pointer to WebAssembly reference type is not allowed}}
   sizeof(ref);                 // expected-error {{invalid application of 'sizeof' to sizeless type '__externref_t'}}
   sizeof(__externref_t);       // expected-error {{invalid application of 'sizeof' to sizeless type '__externref_t'}}
-  sizeof(__externref_t[0]);    // expected-error {{array has sizeless element type '__externref_t'}}
-  sizeof(__externref_t[0][0]); // expected-error {{array has sizeless element type '__externref_t'}}
+  sizeof(__externref_t[0]);    // expected-error {{invalid application of 'sizeof' to WebAssembly table}}
+  sizeof(table);               // expected-error {{invalid application of 'sizeof' to WebAssembly table}}
+  sizeof(__externref_t[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
   sizeof(__externref_t *);     // expected-error {{pointer to WebAssembly reference type is not allowed}}
   sizeof(__externref_t ***);   // expected-error {{pointer to WebAssembly reference type is not allowed}};
   // expected-warning@+1 {{'_Alignof' applied to an expression is a GNU extension}}
   _Alignof(ref);                 // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
   _Alignof(__externref_t);       // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
-  _Alignof(__externref_t[]);     // expected-error {{array has sizeless element type '__externref_t'}}
-  _Alignof(__externref_t[0][0]); // expected-error {{array has sizeless element type '__externref_t'}}
+  _Alignof(__externref_t[]);     // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
+  _Alignof(__externref_t[0]);    // expected-error {{invalid application of 'alignof' to sizeless type '__externref_t'}}
+  _Alignof(table);               // expected-warning {{'_Alignof' applied to an expression is a GNU extension}} expected-error {{invalid application of 'alignof' to WebAssembly table}}
+  _Alignof(__externref_t[0][0]); // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
   _Alignof(__externref_t *);     // expected-error {{pointer to WebAssembly reference type is not allowed}}
   _Alignof(__externref_t ***);   // expected-error {{pointer to WebAssembly reference type is not allowed}};
   varargs(1, ref);               // expected-error {{cannot pass expression of type '__externref_t' to variadic function}}
 
+  __externref_t lt1[0];           // expected-error {{WebAssembly table cannot be declared within a function}}
+  static __externref_t lt2[0];    // expected-error {{WebAssembly table cannot be declared within a function}}
+  static __externref_t lt3[0][0]; // expected-error {{multi-dimensional arrays of WebAssembly references are illegal}}
+  static __externref_t(*lt4)[0];  // expected-error {{cannot form a pointer to a WebAssembly table}}
+  illegal_argument_1(table);      // expected-error {{cannot use WebAssembly table as a function parameter}}
+  varargs(1, table);              // expected-error {{cannot use WebAssembly table as a function parameter}}
+  table == 1;                     // expected-error {{invalid operands to binary expression ('__attribute__((address_space(1))) __externref_t[0]' and 'int')}}
+  1 >= table;                     // expected-error {{invalid operands to binary expression ('int' and '__attribute__((address_space(1))) __externref_t[0]')}}
+  !table;                         // expected-error {{invalid argument type '__attribute__((address_space(1))) __externref_t *' to unary expression}}
+  1 && table;                     // expected-error {{invalid operands to binary expression ('int' and '__attribute__((address_space(1))) __externref_t[0]')}}
+  table || 1;                     // expected-error {{invalid operands to binary expression ('__attribute__((address_space(1))) __externref_t[0]' and 'int')}}
+  1 ? table : table;              // expected-error {{cannot use a WebAssembly table within a branch of a conditional expression}}
+  (void *)table;                  // expected-error {{cannot cast from a WebAssembly table}}
+  void *u;
+  u = table;       // expected-error {{cannot assign a WebAssembly table}}
+  void *v = table; // expected-error {{cannot assign a WebAssembly table}}
+  &table;          // expected-error {{cannot form a reference to a WebAssembly table}}
+  foo ? table : other_table; // expected-error {{cannot use a WebAssembly table within a branch of a conditional expression}}
+  table ? : other_table; // expected-error {{cannot use a WebAssembly table within a branch of a conditional expression}}
+  
+  table[0];
+  table[0] = ref;
   return ref;
 }
+
+void *ret_void_ptr() {
+  return table; // expected-error {{cannot return a WebAssembly table}}
+}
Index: clang/test/Sema/builtins-wasm.c
===================================================================
--- /dev/null
+++ clang/test/Sema/builtins-wasm.c
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-feature +reference-types %s
+
+static __externref_t table[0];
+
+void test_table_size(__externref_t ref, void *ptr, int arr[]) {
+  __builtin_wasm_table_size();                        // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_wasm_table_size(1);                       // expected-error {{1st argument must be a WebAssembly table}}
+  __builtin_wasm_table_size(ref);                     // expected-error {{1st argument must be a WebAssembly table}}
+  __builtin_wasm_table_size(ptr);                     // expected-error {{1st argument must be a WebAssembly table}}
+  __builtin_wasm_table_size(arr);                     // expected-error {{1st argument must be a WebAssembly table}}
+  __builtin_wasm_table_size(table, table);            // expected-error {{too many arguments to function call, expected 1, have 2}}
+  void *a = __builtin_wasm_table_size(table);         // expected-error {{incompatible integer to pointer conversion initializing 'void *' with an expression of type 'int'}}
+  __externref_t b = __builtin_wasm_table_size(table); // expected-error {{initializing '__externref_t' with an expression of incompatible type 'int'}}
+  int c = __builtin_wasm_table_size(table);
+}
+
+void test_table_grow(__externref_t ref, int size) {
+  __builtin_wasm_table_grow();                           // expected-error {{too few arguments to function call, expected 3, have 0}}
+  __builtin_wasm_table_grow(table, table, table, table); // expected-error {{too many arguments to function call, expected 3, have 4}}
+  __builtin_wasm_table_grow(ref, ref, size);             // expected-error {{1st argument must be a WebAssembly table}}
+  __builtin_wasm_table_grow(table, table, size);         // expected-error {{2nd argument must match the element type of the WebAssembly table in the 1st argument}}
+  __builtin_wasm_table_grow(table, ref, table);          // expected-error {{3rd argument must be an integer}}
+  void *a = __builtin_wasm_table_grow(table, ref, size); // expected-error {{incompatible integer to pointer conversion initializing 'void *' with an expression of type 'int'}}
+  int b = __builtin_wasm_table_grow(table, ref, size);
+}
+
+void test_table_fill(int index, __externref_t ref, int nelem) {
+  __builtin_wasm_table_fill();                                   // expected-error {{too few arguments to function call, expected 4, have 0}}
+  __builtin_wasm_table_fill(table, table, table, table, table);  // expected-error {{too many arguments to function call, expected 4, have 5}}
+  __builtin_wasm_table_fill(index, index, ref, nelem);           // expected-error {{1st argument must be a WebAssembly table}}
+  __builtin_wasm_table_fill(table, table, ref, nelem);           // expected-error {{2nd argument must be an integer}}
+  __builtin_wasm_table_fill(table, index, index, ref);           // expected-error {{3rd argument must match the element type of the WebAssembly table in the 1st argument}}
+  __builtin_wasm_table_fill(table, index, ref, table);           // expected-error {{4th argument must be an integer}}
+  void *a = __builtin_wasm_table_fill(table, index, ref, nelem); // expected-error {{initializing 'void *' with an expression of incompatible type 'void'}}
+  __builtin_wasm_table_fill(table, index, ref, nelem);
+}
+
+void test_table_copy(int dst_idx, int src_idx, int nelem) {
+  __builtin_wasm_table_copy();                                         // expected-error {{too few arguments to function call, expected 5, have 0}}
+  __builtin_wasm_table_copy(table, table, table, table, table, table); // expected-error {{too many arguments to function call, expected 5, have 6}}
+  __builtin_wasm_table_copy(src_idx, table, dst_idx, src_idx, nelem);  // expected-error {{1st argument must be a WebAssembly table}}
+  __builtin_wasm_table_copy(table, src_idx, dst_idx, src_idx, nelem);  // expected-error {{2nd argument must be a WebAssembly table}}
+  __builtin_wasm_table_copy(table, table, table, src_idx, nelem);      // expected-error {{3rd argument must be an integer}}
+  __builtin_wasm_table_copy(table, table, dst_idx, table, nelem);      // expected-error {{4th argument must be an integer}}
+  __builtin_wasm_table_copy(table, table, dst_idx, src_idx, table);    // expected-error {{5th argument must be an integer}}
+  __builtin_wasm_table_copy(table, table, dst_idx, src_idx, nelem);
+}
Index: clang/test/CodeGen/WebAssembly/table.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/WebAssembly/table.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple wasm32 -target-feature +reference-types -o - -emit-llvm %s | FileCheck %s
+// REQUIRES: webassembly-registered-target
+
+// CHECK: @table = internal addrspace(1) global [0 x ptr addrspace(10)] zeroinitializer, align 1
+static __externref_t table[0];
+
+void use() {
+  // Ensure the table isn't discarded as unused.
+  table[0];
+}
Index: clang/test/CodeGen/WebAssembly/builtins-table.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/WebAssembly/builtins-table.c
@@ -0,0 +1,67 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature
+// RUN: %clang_cc1 -triple wasm32 -target-feature +reference-types -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck %s
+// REQUIRES: webassembly-registered-target
+
+static __externref_t table[0];
+
+// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_get
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call ptr addrspace(10) @llvm.wasm.table.get.externref(ptr addrspace(1) @table, i32 [[INDEX]])
+// CHECK-NEXT:    ret ptr addrspace(10) [[TMP0]]
+//
+__externref_t test_builtin_wasm_table_get(int index) {
+  return __builtin_wasm_table_get(table, index);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_set
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) @table, i32 [[INDEX]], ptr addrspace(10) [[REF]])
+// CHECK-NEXT:    ret void
+//
+void test_builtin_wasm_table_set(int index, __externref_t ref) {
+  return __builtin_wasm_table_set(table, index, ref);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_size
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.wasm.table.size(ptr addrspace(1) @table)
+// CHECK-NEXT:    ret i32 [[TMP0]]
+//
+int test_builtin_wasm_table_size() {
+  return __builtin_wasm_table_size(table);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_grow
+// CHECK-SAME: (ptr addrspace(10) [[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.wasm.table.grow.externref(ptr addrspace(1) @table, ptr addrspace(10) [[REF]], i32 [[NELEM]])
+// CHECK-NEXT:    ret i32 [[TMP0]]
+//
+int test_builtin_wasm_table_grow(__externref_t ref, int nelem) {
+  return __builtin_wasm_table_grow(table, ref, nelem);
+}
+
+// CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_fill
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.wasm.table.fill.externref(ptr addrspace(1) @table, i32 [[INDEX]], ptr addrspace(10) [[REF]], i32 [[NELEM]])
+// CHECK-NEXT:    ret void
+//
+void test_builtin_wasm_table_fill(int index, __externref_t ref, int nelem) {
+  __builtin_wasm_table_fill(table, index, ref, nelem);
+}
+
+static __externref_t other_table[0];
+
+// CHECK-LABEL: define {{[^@]+}}@test_table_copy
+// CHECK-SAME: (i32 noundef [[DST_IDX:%.*]], i32 noundef [[SRC_IDX:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    call void @llvm.wasm.table.copy(ptr addrspace(1) @table, ptr addrspace(1) @other_table, i32 [[SRC_IDX]], i32 [[DST_IDX]], i32 [[NELEM]])
+// CHECK-NEXT:    ret void
+//
+void test_table_copy(int dst_idx, int src_idx, int nelem) {
+  __builtin_wasm_table_copy(table, other_table, dst_idx, src_idx, nelem);
+}
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -2197,11 +2197,19 @@
   if (getLangOpts().OpenCL)
     T = deduceOpenCLPointeeAddrSpace(*this, T);
 
-  // In WebAssembly, pointers to reference types are illegal.
-  if (getASTContext().getTargetInfo().getTriple().isWasm() &&
-      T->isWebAssemblyReferenceType()) {
-    Diag(Loc, diag::err_wasm_reference_pr) << 0;
-    return QualType();
+  // In WebAssembly, pointers to reference types and pointers to tables are
+  // illegal.
+  if (getASTContext().getTargetInfo().getTriple().isWasm()) {
+    if (T.isWebAssemblyReferenceType()) {
+      Diag(Loc, diag::err_wasm_reference_pr) << 0;
+      return QualType();
+    }
+
+    // We need to desugar the type here in case T is a ParenType.
+    if (T->getUnqualifiedDesugaredType()->isWebAssemblyTableType()) {
+      Diag(Loc, diag::err_wasm_table_pr) << 0;
+      return QualType();
+    }
   }
 
   // Build the pointer type.
@@ -2279,11 +2287,15 @@
   if (getLangOpts().OpenCL)
     T = deduceOpenCLPointeeAddrSpace(*this, T);
 
-  // In WebAssembly, references to reference types are illegal.
+  // In WebAssembly, references to reference types and tables are illegal.
   if (getASTContext().getTargetInfo().getTriple().isWasm() &&
-      T->isWebAssemblyReferenceType()) {
+      T.isWebAssemblyReferenceType()) {
     Diag(Loc, diag::err_wasm_reference_pr) << 1;
     return QualType();
+  } 
+  if (T->isWebAssemblyTableType()) {
+    Diag(Loc, diag::err_wasm_table_pr) << 1;
+    return QualType();
   }
 
   // Handle restrict on references.
@@ -2489,12 +2501,22 @@
   } else {
     // C99 6.7.5.2p1: If the element type is an incomplete or function type,
     // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
-    if (RequireCompleteSizedType(Loc, T,
+    if (!T.isWebAssemblyReferenceType() &&
+        RequireCompleteSizedType(Loc, T,
                                  diag::err_array_incomplete_or_sizeless_type))
       return QualType();
   }
 
-  if (T->isSizelessType()) {
+  // Multi-dimensional arrays of WebAssembly references are not allowed.
+  if (Context.getTargetInfo().getTriple().isWasm() && T->isArrayType()) {
+    const auto *ATy = dyn_cast<ArrayType>(T);
+    if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) {
+      Diag(Loc, diag::err_wasm_multidimensional_ref_array);
+      return QualType();
+    }
+  }
+
+  if (T->isSizelessType() && !T.isWebAssemblyReferenceType()) {
     Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T;
     return QualType();
   }
@@ -3002,6 +3024,9 @@
       Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 <<
         FixItHint::CreateInsertion(Loc, "*");
       Invalid = true;
+    } else if (ParamType->isWebAssemblyTableType()) {
+      Diag(Loc, diag::err_wasm_table_as_function_parameter);
+      Invalid = true;
     }
 
     // C++2a [dcl.fct]p4:
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -3969,6 +3969,14 @@
   } else // If we don't have a function/method context, bail.
     return StmtError();
 
+  if (RetValExp) {
+    const auto *ATy = dyn_cast<ArrayType>(RetValExp->getType());
+    if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) {
+      Diag(ReturnLoc, diag::err_wasm_table_artc) << 1;
+      return StmtError();
+    }
+  }
+
   // C++1z: discarded return statements are not considered when deducing a
   // return type.
   if (ExprEvalContexts.back().isDiscardedStatementContext() &&
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -11976,7 +11976,16 @@
 
   S.Diag(PD.first, PD.second, shouldDeferDiags(S, Args, OpLoc));
 
-  NoteCandidates(S, Args, Cands, Opc, OpLoc);
+  // In WebAssembly we don't want to emit further diagnostics if a table is
+  // passed as an argument to a function.
+  bool NoteCands = true;
+  for (const Expr *Arg : Args) {
+    if (Arg->getType()->isWebAssemblyTableType())
+      NoteCands = false;
+  }
+  
+  if (NoteCands)
+    NoteCandidates(S, Args, Cands, Opc, OpLoc);
 
   if (OCD == OCD_AmbiguousCandidates)
     MaybeDiagnoseAmbiguousConstraints(S, {begin(), end()});
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -992,6 +992,13 @@
       return true;
   }
 
+  // Cannot throw WebAssembly tables (throwing WebAssembly references is
+  // caught earlier in this function).
+  if (Ty.isWebAssemblyReferenceType()) {
+    Diag(ThrowLoc, diag::err_wasm_table_artc) << 2 << E->getSourceRange();
+    return true;
+  }
+
   // If the exception has class type, we need additional handling.
   CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
   if (!RD)
@@ -6568,6 +6575,13 @@
   if (IsSizelessVectorConditional)
     return CheckSizelessVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
 
+  // WebAssembly tables are not allowed as conditional LHS or RHS.
+  if (LTy->isWebAssemblyTableType() || RTy->isWebAssemblyTableType()) {
+    Diag(QuestionLoc, diag::err_wasm_table_conditional_expression)
+        << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+    return QualType();
+  }
+  
   // C++11 [expr.cond]p3
   //   Otherwise, if the second and third operand have different types, and
   //   either has (cv) class type [...] an attempt is made to convert each of
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -940,7 +940,7 @@
     return VAK_Invalid;
 
   if (Context.getTargetInfo().getTriple().isWasm() &&
-      Ty->isWebAssemblyReferenceType()) {
+      Ty.isWebAssemblyReferenceType()) {
     return VAK_Invalid;
   }
 
@@ -4298,6 +4298,15 @@
                                       E->getSourceRange(), ExprKind))
     return false;
 
+  // WebAssembly tables are always illegal operands to unary expressions and
+  // type traits.
+  if (Context.getTargetInfo().getTriple().isWasm() &&
+      E->getType()->isWebAssemblyTableType()) {
+    Diag(E->getExprLoc(), diag::err_wasm_table_invalid_uett_operand)
+        << getTraitSpelling(ExprKind);
+    return true;
+  }
+
   // 'alignof' applied to an expression only requires the base element type of
   // the expression to be complete. 'sizeof' requires the expression's type to
   // be complete (and will attempt to complete it if it's an array of unknown
@@ -4413,6 +4422,15 @@
     return true;
   }
 
+  // WebAssembly tables are always illegal operands to unary expressions and
+  // type traits.
+  if (Context.getTargetInfo().getTriple().isWasm() &&
+      ExprType->isWebAssemblyTableType()) {
+    Diag(OpLoc, diag::err_wasm_table_invalid_uett_operand)
+        << getTraitSpelling(ExprKind);
+    return true;
+  }
+
   if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange,
                                        ExprKind))
     return true;
@@ -5826,6 +5844,7 @@
     if (!ResultType.hasQualifiers())
       VK = VK_PRValue;
   } else if (!ResultType->isDependentType() &&
+             !ResultType.isWebAssemblyReferenceType() &&
              RequireCompleteSizedType(
                  LLoc, ResultType,
                  diag::err_subscript_incomplete_or_sizeless_type, BaseExpr))
@@ -7331,6 +7350,16 @@
   TheCall->setType(FuncT->getCallResultType(Context));
   TheCall->setValueKind(Expr::getValueKindForType(FuncT->getReturnType()));
 
+  // WebAssembly tables can't be used as arguments.
+  if (Context.getTargetInfo().getTriple().isWasm()) {
+    for (const Expr *Arg : Args) {
+      if (Arg && Arg->getType()->isWebAssemblyTableType()) {
+        return ExprError(
+            Diag(Arg->getExprLoc(), diag::err_wasm_table_as_function_parameter));
+      }
+    }
+  }
+
   if (Proto) {
     if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, RParenLoc,
                                 IsExecConfig))
@@ -8894,8 +8923,14 @@
   if (LHS.isInvalid() || RHS.isInvalid())
     return QualType();
 
+  // WebAssembly tables are not allowed as conditional LHS or RHS.
   QualType LHSTy = LHS.get()->getType();
   QualType RHSTy = RHS.get()->getType();
+  if (LHSTy->isWebAssemblyTableType() || RHSTy->isWebAssemblyTableType()) {
+    Diag(QuestionLoc, diag::err_wasm_table_conditional_expression)
+        << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+    return QualType();
+  }
 
   // Diagnose attempts to convert between __ibm128, __float128 and long double
   // where such conversions currently can't be handled.
@@ -12676,6 +12711,12 @@
       (RHSType->isArithmeticType() || RHSType->isEnumeralType()))
     return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc);
 
+  if ((LHSType->isPointerType() &&
+       LHSType->getPointeeType().isWebAssemblyReferenceType()) ||
+      (RHSType->isPointerType() &&
+       RHSType->getPointeeType().isWebAssemblyReferenceType()))
+    return InvalidOperands(Loc, LHS, RHS);
+
   const Expr::NullPointerConstantKind LHSNullKind =
       LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
   const Expr::NullPointerConstantKind RHSNullKind =
@@ -13594,6 +13635,16 @@
   if (EnumConstantInBoolContext)
     Diag(Loc, diag::warn_enum_constant_in_bool_context);
 
+  // WebAssembly tables can't be used with logical operators.
+  QualType LHSTy = LHS.get()->getType();
+  QualType RHSTy = RHS.get()->getType();
+  const auto *LHSATy = dyn_cast<ArrayType>(LHSTy);
+  const auto *RHSATy = dyn_cast<ArrayType>(RHSTy);
+  if ((LHSATy && LHSATy->getElementType().isWebAssemblyReferenceType()) ||
+      (RHSATy && RHSATy->getElementType().isWebAssemblyReferenceType())) {
+    return InvalidOperands(Loc, LHS, RHS);
+  }
+
   // Diagnose cases where the user write a logical and/or but probably meant a
   // bitwise one.  We do this when the LHS is a non-bool integer and the RHS
   // is a constant.
@@ -14135,6 +14186,12 @@
     return QualType();
   }
 
+  // WebAssembly tables can't be used on RHS of an assignment expression.
+  if (RHSType->isWebAssemblyTableType()) {
+    Diag(Loc, diag::err_wasm_table_artc) << 0;
+    return QualType();
+  }
+
   AssignConvertType ConvTy;
   if (CompoundType.isNull()) {
     Expr *RHSCheck = RHS.get();
@@ -14510,7 +14567,8 @@
   AO_Property_Expansion = 2,
   AO_Register_Variable = 3,
   AO_Matrix_Element = 4,
-  AO_No_Error = 5
+  AO_Table_Element = 5,
+  AO_No_Error = 6
 };
 }
 /// Diagnose invalid operand for address of operations.
@@ -14681,6 +14739,9 @@
   } else if (op->getObjectKind() == OK_MatrixComponent) {
     // The operand cannot be an element of a matrix.
     AddressOfError = AO_Matrix_Element;
+  } else if (op->getObjectKind() == OK_TableComponent) {
+    // The operand cannot be an element of a table.
+    AddressOfError = AO_Table_Element;
   } else if (dcl) { // C99 6.5.3.2p1
     // We have an lvalue with a decl. Make sure the decl is not declared
     // with the register storage-class specifier.
@@ -14742,11 +14803,19 @@
   if (op->getType()->isObjCObjectType())
     return Context.getObjCObjectPointerType(op->getType());
 
-  if (Context.getTargetInfo().getTriple().isWasm() &&
-      op->getType()->isWebAssemblyReferenceType()) {
-    Diag(OpLoc, diag::err_wasm_ca_reference)
-        << 1 << OrigOp.get()->getSourceRange();
-    return QualType();
+  // Cannot take the address of WebAssembly references or tables.
+  if (Context.getTargetInfo().getTriple().isWasm()) {
+    QualType OpTy = op->getType();
+    if (OpTy.isWebAssemblyReferenceType()) {
+      Diag(OpLoc, diag::err_wasm_ca_reference)
+          << 1 << OrigOp.get()->getSourceRange();
+      return QualType();
+    }
+    if (OpTy->isWebAssemblyTableType()) {
+      Diag(OpLoc, diag::err_wasm_table_pr) << 1
+          << OrigOp.get()->getSourceRange();
+      return QualType();
+    }
   }
 
   CheckAddressOfPackedMember(op);
@@ -15922,6 +15991,13 @@
       resultType = Context.FloatTy;
     }
 
+    // WebAsembly tables can't be used in unary expressions.
+    if (resultType->isPointerType() &&
+        resultType->getPointeeType().isWebAssemblyReferenceType()) {
+      return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+                       << resultType << Input.get()->getSourceRange());
+    }
+
     if (resultType->isDependentType())
       break;
     if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) {
@@ -18856,7 +18932,7 @@
   }
 
   if (BuildAndDiagnose && S.Context.getTargetInfo().getTriple().isWasm() &&
-      CaptureType.getNonReferenceType()->isWebAssemblyReferenceType()) {
+      CaptureType.getNonReferenceType().isWebAssemblyReferenceType()) {
     S.Diag(Loc, diag::err_wasm_ca_reference) << 0;
     Invalid = true;
   }
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -119,6 +119,7 @@
 /// \param[in,out] T  The exception type. This will be decayed to a pointer type
 ///                   when the input is an array or a function type.
 bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
+
   // C++11 [except.spec]p2:
   //   A type cv T, "array of T", or "function returning T" denoted
   //   in an exception-specification is adjusted to type T, "pointer to T", or
@@ -180,6 +181,12 @@
     return true;
   }
 
+  // WebAssembly tables can't be used in exception specifications.
+  if (PointeeT.isWebAssemblyReferenceType()) {
+    Diag(Range.getBegin(), diag::err_wasm_table_exception_spec);
+    return true;
+  }
+
   return false;
 }
 
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16464,6 +16464,11 @@
     Invalid = true;
   }
 
+  if (!Invalid && BaseType.isWebAssemblyReferenceType()) {
+    Diag(Loc, diag::err_wasm_table_artc) << 3;
+    Invalid = true;
+  }
+
   if (!Invalid && !ExDeclType->isDependentType() &&
       RequireNonAbstractType(Loc, ExDeclType,
                              diag::err_abstract_type_in_decl,
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -7833,6 +7833,18 @@
     }
   }
 
+  // WebAssembly tables are always in address space 1 (wasm_var). Don't apply
+  // address space if the table has local storage (semantic checks elsewhere
+  // will produce an error anyway).
+  if (const auto *ATy = dyn_cast<ArrayType>(NewVD->getType())) {
+    if (ATy && ATy->getElementType().isWebAssemblyReferenceType() &&
+        !NewVD->hasLocalStorage()) {
+      QualType Type = Context.getAddrSpaceQualType(
+          NewVD->getType(), Context.getLangASForBuiltinAddressSpace(1));
+      NewVD->setType(Type);
+    }
+  }
+
   // Handle attributes prior to checking for duplicates in MergeVarDecl
   ProcessDeclAttributes(S, NewVD, D);
 
@@ -7989,6 +8001,13 @@
     if (!IsVariableTemplateSpecialization)
       D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
 
+    // CheckVariableDeclaration will set NewVD as invalid if something is in
+    // error like WebAssembly tables being declared as arrays with a non-zero
+    // size, but then parsing continues and emits further errors on that line.
+    // To avoid that we check here if it happened and return nullptr.
+    if (NewVD->getType()->isWebAssemblyTableType() && NewVD->isInvalidDecl())
+      return nullptr;
+
     if (NewTemplate) {
       VarTemplateDecl *PrevVarTemplate =
           NewVD->getPreviousDecl()
@@ -8595,6 +8614,28 @@
     }
   }
 
+  // WebAssembly tables must be static with a zero length and can't be
+  // declared within functions.
+  if (T->isWebAssemblyTableType()) {
+    if (getCurScope()->isFunctionScope()) {
+      Diag(NewVD->getLocation(), diag::err_wasm_table_in_function);
+      NewVD->setInvalidDecl();
+      return;
+    }
+    if (NewVD->getStorageClass() != SC_Static) {
+      Diag(NewVD->getLocation(), diag::err_wasm_table_must_be_static);
+      NewVD->setInvalidDecl();
+      return;
+    }
+    const auto *ATy = dyn_cast<ConstantArrayType>(T.getTypePtr());
+    if (!ATy || ATy->getSize().getSExtValue() != 0) {
+      Diag(NewVD->getLocation(),
+           diag::err_typecheck_wasm_table_must_have_zero_length);
+      NewVD->setInvalidDecl();
+      return;
+    }
+  }
+
   bool isVM = T->isVariablyModifiedType();
   if (isVM || NewVD->hasAttr<CleanupAttr>() ||
       NewVD->hasAttr<BlocksAttr>())
@@ -8666,7 +8707,7 @@
   }
 
   if (!NewVD->hasLocalStorage() && T->isSizelessType() &&
-      !T->isWebAssemblyReferenceType()) {
+      !T.isWebAssemblyReferenceType()) {
     Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T;
     NewVD->setInvalidDecl();
     return;
@@ -10664,6 +10705,14 @@
           }
       }
     }
+    // WebAssembly tables can't be used as function parameters.
+    if (Context.getTargetInfo().getTriple().isWasm()) {
+      if (PT->getUnqualifiedDesugaredType()->isWebAssemblyTableType()) {
+        Diag(Param->getTypeSpecStartLoc(),
+             diag::err_wasm_table_as_function_parameter);
+        D.setInvalidType();
+      }
+    }
   }
 
   // Here we have an function template explicit specialization at class scope.
@@ -13025,6 +13074,14 @@
     return;
   }
 
+  // WebAssembly tables can't be used to initialise a variable.
+  if (Init && !Init->getType().isNull() &&
+      Init->getType()->isWebAssemblyTableType()) {
+    Diag(Init->getExprLoc(), diag::err_wasm_table_artc) << 0;
+    VDecl->setInvalidDecl();
+    return;
+  }
+
   // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
   if (VDecl->getType()->isUndeducedType()) {
     // Attempt typo correction early so that the type of the init expression can
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -4717,6 +4717,18 @@
     return BuiltinWasmRefNullExtern(TheCall);
   case WebAssembly::BI__builtin_wasm_ref_null_func:
     return BuiltinWasmRefNullFunc(TheCall);
+  case WebAssembly::BI__builtin_wasm_table_get:
+    return BuiltinWasmTableGet(TheCall);
+  case WebAssembly::BI__builtin_wasm_table_set:
+    return BuiltinWasmTableSet(TheCall);
+  case WebAssembly::BI__builtin_wasm_table_size:
+    return BuiltinWasmTableSize(TheCall);
+  case WebAssembly::BI__builtin_wasm_table_grow:
+    return BuiltinWasmTableGrow(TheCall);
+  case WebAssembly::BI__builtin_wasm_table_fill:
+    return BuiltinWasmTableFill(TheCall);
+  case WebAssembly::BI__builtin_wasm_table_copy:
+    return BuiltinWasmTableCopy(TheCall);
   }
 
   return false;
@@ -12187,6 +12199,10 @@
     }
   }
 
+  if (RetValExp && RetValExp->getType()->isWebAssemblyTableType()) {
+    Diag(ReturnLoc, diag::err_wasm_table_artc) << 1;
+  }
+
   // PPC MMA non-pointer types are not allowed as return type. Checking the type
   // here prevent the user from using a PPC MMA type as trailing return type.
   if (Context.getTargetInfo().getTriple().isPPC64())
@@ -15880,6 +15896,13 @@
                                      RD, /*DeclIsField*/ false);
       }
     }
+
+    if (!Param->isInvalidDecl() &&
+        Param->getOriginalType()->isWebAssemblyTableType()) {
+      Param->setInvalidDecl();
+      HasInvalidParm = true;
+      Diag(Param->getLocation(), diag::err_wasm_table_as_function_parameter);
+    }
   }
 
   return HasInvalidParm;
@@ -18114,6 +18137,168 @@
   return CallResult;
 }
 
+/// Checks the argument at the given index is a WebAssembly table and if it
+/// is, sets ElTy to the element type.
+static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex,
+                                       QualType &ElTy) {
+  Expr *ArgExpr = E->getArg(ArgIndex);
+  const auto *ATy = dyn_cast<ArrayType>(ArgExpr->getType());
+  if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) {
+    return S.Diag(ArgExpr->getBeginLoc(),
+                  diag::err_wasm_builtin_arg_must_be_table_type)
+           << ArgIndex + 1 << ArgExpr->getSourceRange();
+  }
+  ElTy = ATy->getElementType();
+  return false;
+}
+
+/// Checks the argument at the given index is an integer.
+static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E,
+                                         unsigned ArgIndex) {
+  Expr *ArgExpr = E->getArg(ArgIndex);
+  if (!ArgExpr->getType()->isIntegerType()) {
+    return S.Diag(ArgExpr->getBeginLoc(),
+                  diag::err_wasm_builtin_arg_must_be_integer_type)
+           << ArgIndex + 1 << ArgExpr->getSourceRange();
+  }
+  return false;
+}
+
+/// Check that the first argument is a WebAssembly table, and the second
+/// is an index to use as index into the table. 
+bool Sema::BuiltinWasmTableGet(CallExpr *TheCall) {
+  if (checkArgCount(*this, TheCall, 2))
+    return true;
+
+  QualType ElTy;
+  if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
+    return true;
+
+  if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1))
+    return true;
+
+  // If all is well, we set the type of TheCall to be the type of the
+  // element of the table.
+  // i.e. a table.get on an externref table has type externref,
+  // or whatever the type of the table element is.
+  TheCall->setType(ElTy);
+  
+  return false;
+}
+
+/// Check that the first argumnet is a WebAssembly table, the second is
+/// an index to use as index into the table and the third is the reference
+/// type to set into the table.
+bool Sema::BuiltinWasmTableSet(CallExpr *TheCall) {
+  if (checkArgCount(*this, TheCall, 3))
+    return true;
+
+  QualType ElTy;
+  if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
+    return true;
+
+  if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1))
+    return true;
+
+  if (!Context.hasSameType(ElTy, TheCall->getArg(2)->getType()))
+    return true;
+
+  return false;
+}
+
+/// Check that the argument is a WebAssembly table.
+bool Sema::BuiltinWasmTableSize(CallExpr *TheCall) {
+  if (checkArgCount(*this, TheCall, 1))
+    return true;
+
+  QualType ElTy;
+  if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
+    return true;
+
+  return false;
+}
+
+/// Check that the first argument is a WebAssembly table, the second is the
+/// value to use for new elements (of a type matching the table type), the
+/// third value is an integer.
+bool Sema::BuiltinWasmTableGrow(CallExpr *TheCall) {
+  if (checkArgCount(*this, TheCall, 3))
+    return true;
+
+  QualType ElTy;
+  if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
+    return true;
+
+  Expr *NewElemArg = TheCall->getArg(1);
+  if (!Context.hasSameType(ElTy, NewElemArg->getType())) {
+    return Diag(NewElemArg->getBeginLoc(),
+                diag::err_wasm_builtin_arg_must_match_table_element_type)
+           << 2 << 1 << NewElemArg->getSourceRange();
+  }
+
+  if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 2))
+    return true;
+
+  return false;
+}
+
+/// Check that the first argument is a WebAssembly table, the second is an
+/// integer, the third is the value to use to fill the table (of a type
+/// matching the table type), and the fourth is an integer.
+bool Sema::BuiltinWasmTableFill(CallExpr *TheCall) {
+  if (checkArgCount(*this, TheCall, 4))
+    return true;
+
+  QualType ElTy;
+  if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy))
+    return true;
+
+  if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1))
+    return true;
+
+  Expr *NewElemArg = TheCall->getArg(2);
+  if (!Context.hasSameType(ElTy, NewElemArg->getType())) {
+    return Diag(NewElemArg->getBeginLoc(),
+                diag::err_wasm_builtin_arg_must_match_table_element_type)
+           << 3 << 1 << NewElemArg->getSourceRange();
+  }
+
+  if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 3))
+    return true;
+
+  return false;
+}
+
+/// Check that the first argument is a WebAssembly table, the second is also a
+/// WebAssembly table (of the same element type), and the third to fifth
+/// arguments are integers.
+bool Sema::BuiltinWasmTableCopy(CallExpr *TheCall) {
+  if (checkArgCount(*this, TheCall, 5))
+    return true;
+
+  QualType XElTy;
+  if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, XElTy))
+    return true;
+
+  QualType YElTy;
+  if (CheckWasmBuiltinArgIsTable(*this, TheCall, 1, YElTy))
+    return true;
+
+  Expr *TableYArg = TheCall->getArg(1);
+  if (!Context.hasSameType(XElTy, YElTy)) {
+    return Diag(TableYArg->getBeginLoc(),
+                diag::err_wasm_builtin_arg_must_match_table_element_type)
+           << 2 << 1 << TableYArg->getSourceRange();
+  }
+
+  for (int I = 2; I <= 4; I++) {
+    if (CheckWasmBuiltinArgIsInteger(*this, TheCall, I))
+      return true;
+  }
+
+  return false;
+}
+
 /// \brief Enforce the bounds of a TCB
 /// CheckTCBEnforcement - Enforces that every function in a named TCB only
 /// directly calls other functions in the same TCB as marked by the enforce_tcb
Index: clang/lib/Sema/SemaCast.cpp
===================================================================
--- clang/lib/Sema/SemaCast.cpp
+++ clang/lib/Sema/SemaCast.cpp
@@ -2262,6 +2262,9 @@
     case OK_MatrixComponent:
       inappropriate = "matrix element";
       break;
+    case OK_TableComponent:
+      inappropriate = "table element";
+      break;
     case OK_ObjCProperty:    inappropriate = "property expression"; break;
     case OK_ObjCSubscript:   inappropriate = "container subscripting expression";
                              break;
@@ -2736,6 +2739,15 @@
     }
   }
 
+  // WebAssembly tables cannot be cast.
+  QualType SrcType = SrcExpr.get()->getType();
+  if (SrcType->isWebAssemblyTableType()) {
+    Self.Diag(OpRange.getBegin(), diag::err_wasm_cast_table) << 1
+        << SrcExpr.get()->getSourceRange();
+    SrcExpr = ExprError();
+    return;
+  }
+
   // C++ [expr.cast]p5: The conversions performed by
   //   - a const_cast,
   //   - a static_cast,
@@ -2911,6 +2923,13 @@
     return;
   QualType SrcType = SrcExpr.get()->getType();
 
+  if (SrcType->isWebAssemblyTableType()) {
+    Self.Diag(OpRange.getBegin(), diag::err_wasm_cast_table) << 1
+        << SrcExpr.get()->getSourceRange();
+    SrcExpr = ExprError();
+    return;
+  }
+
   assert(!SrcType->isPlaceholderType());
 
   checkAddressSpaceCast(SrcType, DestType);
Index: clang/lib/CodeGen/CGValue.h
===================================================================
--- clang/lib/CodeGen/CGValue.h
+++ clang/lib/CodeGen/CGValue.h
@@ -175,7 +175,8 @@
     BitField,     // This is a bitfield l-value, use getBitfield*.
     ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
     GlobalReg,    // This is a register l-value, use getGlobalReg()
-    MatrixElt     // This is a matrix element, use getVector*
+    MatrixElt,    // This is a matrix element, use getVector*
+    TableElt,     // This is a table element, use getTable*
   } LVType;
 
   llvm::Value *V;
@@ -268,6 +269,7 @@
   bool isExtVectorElt() const { return LVType == ExtVectorElt; }
   bool isGlobalReg() const { return LVType == GlobalReg; }
   bool isMatrixElt() const { return LVType == MatrixElt; }
+  bool isTableElt() const { return LVType == TableElt; }
 
   bool isVolatileQualified() const { return Quals.hasVolatile(); }
   bool isRestrictQualified() const { return Quals.hasRestrict(); }
@@ -373,6 +375,19 @@
     return VectorIdx;
   }
 
+  Address getTableAddress() const {
+    // FIXME: maybe this should not be possible.
+    return Address(getTablePointer(), ElementType, getAlignment());
+  }
+  llvm::Value *getTablePointer() const {
+    assert(isTableElt());
+    return V;
+  }
+  llvm::Value *getTableIdx() const {
+    assert(isTableElt());
+    return VectorIdx;
+  }
+
   // extended vector elements.
   Address getExtVectorAddress() const {
     return Address(getExtVectorPointer(), ElementType, getAlignment());
@@ -482,6 +497,19 @@
     return R;
   }
 
+  static LValue MakeTableElt(Address tabAddress, llvm::Value *Idx,
+                             QualType type, LValueBaseInfo BaseInfo,
+                             TBAAAccessInfo TBAAInfo) {
+    LValue R;
+    R.LVType = TableElt;
+    R.V = tabAddress.getPointer();
+    R.ElementType = tabAddress.getElementType();
+    R.VectorIdx = Idx;
+    R.Initialize(type, type.getQualifiers(), tabAddress.getAlignment(),
+                 BaseInfo, TBAAInfo);
+    return R;
+  }
+
   RValue asAggregateRValue(CodeGenFunction &CGF) const {
     return RValue::getAggregate(getAddress(CGF), isVolatileQualified());
   }
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -33,9 +33,11 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicsWebAssembly.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/MatrixBuilder.h"
+#include "llvm/Passes/OptimizationLevel.h"
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/Path.h"
@@ -153,6 +155,7 @@
         Builder.CreateBitCast(Result.getPointer(), VectorTy->getPointerTo()),
         VectorTy, Result.getAlignment());
   }
+  
   return Result;
 }
 
@@ -1936,7 +1939,7 @@
 
     if (LV.getType()->isConstantMatrixType())
       return EmitLoadOfMatrixLValue(LV, Loc, *this);
-
+    
     // Everything needs a load.
     return RValue::get(EmitLoadOfScalar(LV, Loc));
   }
@@ -1965,6 +1968,7 @@
       llvm::MatrixBuilder MB(Builder);
       MB.CreateIndexAssumption(Idx, MatTy->getNumElementsFlattened());
     }
+
     llvm::LoadInst *Load =
         Builder.CreateLoad(LV.getMatrixAddress(), LV.isVolatileQualified());
     return RValue::get(Builder.CreateExtractElement(Load, Idx, "matrixext"));
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -19196,6 +19196,95 @@
         CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_bf16x8_add_f32);
     return Builder.CreateCall(Callee, {LHS, RHS, Acc});
   }
+  case WebAssembly::BI__builtin_wasm_table_get: {
+    assert(E->getArg(0)->getType()->isArrayType());
+    Value *Table =
+        EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
+    Value *Index = EmitScalarExpr(E->getArg(1));
+    Function *Callee;
+    if (E->getType().isWebAssemblyExternrefType())
+      Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_externref);
+    else if (E->getType().isWebAssemblyFuncrefType())
+      Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_funcref);
+    else
+      llvm_unreachable(
+          "Unexpected reference type for __builtin_wasm_table_get");
+    return Builder.CreateCall(Callee, {Table, Index});
+  }
+  case WebAssembly::BI__builtin_wasm_table_set: {
+    assert(E->getArg(0)->getType()->isArrayType());
+    Value *Table =
+        EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
+    Value *Index = EmitScalarExpr(E->getArg(1));
+    Value *Val = EmitScalarExpr(E->getArg(2));
+    Function *Callee;
+    if (E->getArg(2)->getType().isWebAssemblyExternrefType())
+      Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_externref);
+    else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
+      Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_funcref);
+    else
+      llvm_unreachable(
+          "Unexpected reference type for __builtin_wasm_table_set");
+    return Builder.CreateCall(Callee, {Table, Index, Val});
+  }
+  case WebAssembly::BI__builtin_wasm_table_size: {
+    assert(E->getArg(0)->getType()->isArrayType());
+    Value *Value =
+        EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
+    Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size);
+    return Builder.CreateCall(Callee, Value);
+  }
+  case WebAssembly::BI__builtin_wasm_table_grow: {
+    assert(E->getArg(0)->getType()->isArrayType());
+    Value *Table =
+        EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
+    Value *Val = EmitScalarExpr(E->getArg(1));
+    Value *NElems = EmitScalarExpr(E->getArg(2));
+
+    Function *Callee;
+    if (E->getArg(1)->getType().isWebAssemblyExternrefType())
+      Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_externref);
+    else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
+      Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref);
+    else
+      llvm_unreachable(
+          "Unexpected reference type for __builtin_wasm_table_grow");
+
+    return Builder.CreateCall(Callee, {Table, Val, NElems});
+  }
+  case WebAssembly::BI__builtin_wasm_table_fill: {
+    assert(E->getArg(0)->getType()->isArrayType());
+    Value *Table =
+        EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
+    Value *Index = EmitScalarExpr(E->getArg(1));
+    Value *Val = EmitScalarExpr(E->getArg(2));
+    Value *NElems = EmitScalarExpr(E->getArg(3));
+
+    Function *Callee;
+    if (E->getArg(2)->getType().isWebAssemblyExternrefType())
+      Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_externref);
+    else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
+      Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref);
+    else
+      llvm_unreachable(
+          "Unexpected reference type for __builtin_wasm_table_fill");
+
+    return Builder.CreateCall(Callee, {Table, Index, Val, NElems});
+  }
+  case WebAssembly::BI__builtin_wasm_table_copy: {
+    assert(E->getArg(0)->getType()->isArrayType());
+    Value *TableX =
+        EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(0)).getPointer());
+    Value *TableY =
+        EmitCastToVoidPtr(EmitArrayToPointerDecay(E->getArg(1)).getPointer());
+    Value *DstIdx = EmitScalarExpr(E->getArg(2));
+    Value *SrcIdx = EmitScalarExpr(E->getArg(3));
+    Value *NElems = EmitScalarExpr(E->getArg(4));
+
+    Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_copy);
+
+    return Builder.CreateCall(Callee, {TableX, TableY, SrcIdx, DstIdx, NElems});
+  }
   default:
     return nullptr;
   }
Index: clang/lib/Basic/Targets/WebAssembly.cpp
===================================================================
--- clang/lib/Basic/Targets/WebAssembly.cpp
+++ clang/lib/Basic/Targets/WebAssembly.cpp
@@ -151,6 +151,7 @@
     Features["atomics"] = true;
     Features["mutable-globals"] = true;
     Features["tail-call"] = true;
+    Features["reference-types"] = true;
     setSIMDLevel(Features, SIMD128, true);
   } else if (CPU == "generic") {
     Features["sign-ext"] = true;
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -2346,16 +2346,22 @@
   return false;
 }
 
-bool Type::isWebAssemblyReferenceType() const {
-  return isWebAssemblyExternrefType();
-}
-
 bool Type::isWebAssemblyExternrefType() const {
   if (const auto *BT = getAs<BuiltinType>())
     return BT->getKind() == BuiltinType::WasmExternRef;
   return false;
 }
 
+bool Type::isWebAssemblyTableType() const {
+  if (const auto *ATy = dyn_cast<ArrayType>(this))
+    return ATy->getElementType().isWebAssemblyReferenceType();
+
+  if (const auto *PTy = dyn_cast<PointerType>(this))
+    return PTy->getPointeeType().isWebAssemblyReferenceType();
+
+  return false;
+}
+
 bool Type::isSizelessType() const { return isSizelessBuiltinType(); }
 
 bool Type::isSVESizelessBuiltinType() const {
@@ -2594,6 +2600,18 @@
   return RD->hasNonTrivialToPrimitiveCopyCUnion();
 }
 
+bool QualType::isWebAssemblyReferenceType() const {
+  return isWebAssemblyExternrefType() || isWebAssemblyFuncrefType();
+}
+
+bool QualType::isWebAssemblyExternrefType() const {
+  return getTypePtr()->isWebAssemblyExternrefType();
+}
+
+bool QualType::isWebAssemblyFuncrefType() const {
+  return getTypePtr()->isFunctionPointerType() && getAddressSpace() == LangAS::wasm_funcref;
+}
+
 QualType::PrimitiveDefaultInitializeKind
 QualType::isNonTrivialToPrimitiveDefaultInitialize() const {
   if (const auto *RT =
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -176,6 +176,9 @@
       case OK_MatrixComponent:
         OS << " matrixcomponent";
         break;
+      case OK_TableComponent:
+        OS << " tablecomponent";
+        break;
       }
     }
   }
Index: clang/include/clang/Serialization/TypeBitCodes.def
===================================================================
--- clang/include/clang/Serialization/TypeBitCodes.def
+++ clang/include/clang/Serialization/TypeBitCodes.def
@@ -64,5 +64,4 @@
 TYPE_BIT_CODE(DependentSizedMatrix, DEPENDENT_SIZE_MATRIX, 53)
 TYPE_BIT_CODE(Using, USING, 54)
 TYPE_BIT_CODE(BTFTagAttributed, BTFTAG_ATTRIBUTED, 55)
-
 #undef TYPE_BIT_CODE
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1651,7 +1651,7 @@
 
   /// An MatrixSubscriptExpr record.
   EXPR_MATRIX_SUBSCRIPT,
-
+  
   /// A CallExpr record.
   EXPR_CALL,
 
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -13529,6 +13529,12 @@
   // WebAssembly builtin handling.
   bool BuiltinWasmRefNullExtern(CallExpr *TheCall);
   bool BuiltinWasmRefNullFunc(CallExpr *TheCall);
+  bool BuiltinWasmTableGet(CallExpr *TheCall);
+  bool BuiltinWasmTableSet(CallExpr *TheCall);
+  bool BuiltinWasmTableSize(CallExpr *TheCall);
+  bool BuiltinWasmTableGrow(CallExpr *TheCall);
+  bool BuiltinWasmTableFill(CallExpr *TheCall);
+  bool BuiltinWasmTableCopy(CallExpr *TheCall);
 
 public:
   enum FormatStringType {
Index: clang/include/clang/Basic/Specifiers.h
===================================================================
--- clang/include/clang/Basic/Specifiers.h
+++ clang/include/clang/Basic/Specifiers.h
@@ -154,7 +154,10 @@
     OK_ObjCSubscript,
 
     /// A matrix component is a single element of a matrix.
-    OK_MatrixComponent
+    OK_MatrixComponent,
+
+    /// A table component is a single element of a WebAssembly table.
+    OK_TableComponent,
   };
 
   /// The reason why a DeclRefExpr does not constitute an odr-use.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11787,4 +11787,32 @@
   "cannot %select{capture|take address of}0 WebAssembly reference">;
 def err_wasm_funcref_not_wasm : Error<
   "invalid use of __funcref keyword outside the WebAssembly triple">;
+def err_wasm_table_pr : Error<
+  "cannot form a %select{pointer|reference}0 to a WebAssembly table">;
+def err_typecheck_wasm_table_must_have_zero_length : Error<
+  "only zero-length WebAssembly tables are currently supported">;
+def err_wasm_table_in_function : Error<
+  "WebAssembly table cannot be declared within a function">;
+def err_wasm_table_as_function_parameter : Error<
+  "cannot use WebAssembly table as a function parameter">;
+def err_wasm_table_invalid_uett_operand : Error<
+  "invalid application of '%0' to WebAssembly table">;
+def err_wasm_cast_table : Error<
+  "cannot cast %select{to|from}0 a WebAssembly table">;
+def err_wasm_table_conditional_expression : Error<
+  "cannot use a WebAssembly table within a branch of a conditional expression">;
+def err_wasm_table_artc : Error<
+  "cannot %select{assign|return|throw|catch}0 a WebAssembly table">;
+def err_wasm_table_exception_spec : Error<
+  "WebAssembly table not allowed in exception specification">;
+def err_wasm_table_must_be_static : Error<
+  "WebAssembly table must be static">;
+def err_wasm_multidimensional_ref_array : Error<
+  "multi-dimensional arrays of WebAssembly references are illegal">;
+def err_wasm_builtin_arg_must_be_table_type : Error <
+  "%ordinal0 argument must be a WebAssembly table">;
+def err_wasm_builtin_arg_must_match_table_element_type : Error <
+  "%ordinal0 argument must match the element type of the WebAssembly table in the %ordinal1 argument">;
+def err_wasm_builtin_arg_must_be_integer_type : Error <
+  "%ordinal0 argument must be an integer">;
 } // end of sema component.
Index: clang/include/clang/Basic/BuiltinsWebAssembly.def
===================================================================
--- clang/include/clang/Basic/BuiltinsWebAssembly.def
+++ clang/include/clang/Basic/BuiltinsWebAssembly.def
@@ -201,5 +201,13 @@
 // return type.
 TARGET_BUILTIN(__builtin_wasm_ref_null_func, "i", "nct", "reference-types")
 
+// Table builtins
+TARGET_BUILTIN(__builtin_wasm_table_set,  "viii", "t", "reference-types")
+TARGET_BUILTIN(__builtin_wasm_table_get,  "iii", "t", "reference-types")
+TARGET_BUILTIN(__builtin_wasm_table_size, "ii", "nt", "reference-types")
+TARGET_BUILTIN(__builtin_wasm_table_grow, "iiii", "nt", "reference-types")
+TARGET_BUILTIN(__builtin_wasm_table_fill, "viiii", "t", "reference-types")
+TARGET_BUILTIN(__builtin_wasm_table_copy, "viiiii", "t", "reference-types")
+
 #undef BUILTIN
 #undef TARGET_BUILTIN
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -905,6 +905,15 @@
   /// Returns true if it is not a class or if the class might not be dynamic.
   bool mayBeNotDynamicClass() const;
 
+  /// Returns true if it is a WebAssembly Reference Type.
+  bool isWebAssemblyReferenceType() const;
+
+  /// Returns true if it is a WebAssembly Externref Type.
+  bool isWebAssemblyExternrefType() const;
+
+  /// Returns true if it is a WebAssembly Funcref Type.
+  bool isWebAssemblyFuncrefType() const;
+
   // Don't promise in the API that anything besides 'const' can be
   // easily added.
 
@@ -2029,10 +2038,14 @@
   /// Returns true for SVE scalable vector types.
   bool isSVESizelessBuiltinType() const;
 
-  /// Check if this is a WebAssembly Reference Type.
-  bool isWebAssemblyReferenceType() const;
+  /// Check if this is a WebAssembly Externref Type.
   bool isWebAssemblyExternrefType() const;
 
+  /// Returns true if this is a WebAssembly table type: either an array of
+  /// reference types, or a pointer to a reference type (which can only be
+  /// created by array to pointer decay).
+  bool isWebAssemblyTableType() const;
+
   /// Determines if this is a sizeless type supported by the
   /// 'arm_sve_vector_bits' type attribute, which can be applied to a single
   /// SVE vector or predicate, excluding tuple types such as svint32x4_t.
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -453,7 +453,7 @@
     unsigned IsType : 1; // true if operand is a type, false if an expression.
   };
 
-  class ArrayOrMatrixSubscriptExprBitfields {
+  class AMTSubscriptExprBitfields {
     friend class ArraySubscriptExpr;
     friend class MatrixSubscriptExpr;
 
@@ -1042,7 +1042,7 @@
     CharacterLiteralBitfields CharacterLiteralBits;
     UnaryOperatorBitfields UnaryOperatorBits;
     UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits;
-    ArrayOrMatrixSubscriptExprBitfields ArrayOrMatrixSubscriptExprBits;
+    AMTSubscriptExprBitfields AMTSubscriptExprBits;
     CallExprBitfields CallExprBits;
     MemberExprBitfields MemberExprBits;
     CastExprBitfields CastExprBits;
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -2665,7 +2665,7 @@
       : Expr(ArraySubscriptExprClass, t, VK, OK) {
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
-    ArrayOrMatrixSubscriptExprBits.RBracketLoc = rbracketloc;
+    AMTSubscriptExprBits.RBracketLoc = rbracketloc;
     setDependence(computeDependence(this));
   }
 
@@ -2702,10 +2702,10 @@
   SourceLocation getEndLoc() const { return getRBracketLoc(); }
 
   SourceLocation getRBracketLoc() const {
-    return ArrayOrMatrixSubscriptExprBits.RBracketLoc;
+    return AMTSubscriptExprBits.RBracketLoc;
   }
   void setRBracketLoc(SourceLocation L) {
-    ArrayOrMatrixSubscriptExprBits.RBracketLoc = L;
+    AMTSubscriptExprBits.RBracketLoc = L;
   }
 
   SourceLocation getExprLoc() const LLVM_READONLY {
@@ -2743,7 +2743,7 @@
     SubExprs[BASE] = Base;
     SubExprs[ROW_IDX] = RowIdx;
     SubExprs[COLUMN_IDX] = ColumnIdx;
-    ArrayOrMatrixSubscriptExprBits.RBracketLoc = RBracketLoc;
+    AMTSubscriptExprBits.RBracketLoc = RBracketLoc;
     setDependence(computeDependence(this));
   }
 
@@ -2784,10 +2784,10 @@
   }
 
   SourceLocation getRBracketLoc() const {
-    return ArrayOrMatrixSubscriptExprBits.RBracketLoc;
+    return AMTSubscriptExprBits.RBracketLoc;
   }
   void setRBracketLoc(SourceLocation L) {
-    ArrayOrMatrixSubscriptExprBits.RBracketLoc = L;
+    AMTSubscriptExprBits.RBracketLoc = L;
   }
 
   static bool classof(const Stmt *T) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to