https://github.com/hoodmane updated 
https://github.com/llvm/llvm-project/pull/205817

>From d4223c5748d0c0447e8d755325d305fe04978d4c Mon Sep 17 00:00:00 2001
From: Hood Chatham <[email protected]>
Date: Thu, 4 Jun 2026 14:42:11 -0700
Subject: [PATCH 1/2] Add WebAssemblyTableType

This adds a new WebAssemblyTableType to the Clang IR intended to represent
WebAssembly tables. It does not use it anywhere yet.
These correspond to llvm_table_ty in llvm ir and tableidx immediates in llvm ir.
Because a tableidx is an immediate, these are not really values at all. All
values of this type must be global variables and they cannot be used anywhere
other than arguments to wasm table builtins like __builtin_wasm_table_get().
---
 clang/include/clang/AST/ASTContext.h          |  5 ++
 clang/include/clang/AST/RecursiveASTVisitor.h |  6 +++
 clang/include/clang/AST/TypeBase.h            | 34 +++++++++++++
 clang/include/clang/AST/TypeLoc.h             | 23 +++++++++
 clang/include/clang/AST/TypeProperties.td     | 10 ++++
 clang/include/clang/Basic/TypeNodes.td        |  1 +
 .../clang/Serialization/TypeBitCodes.def      |  1 +
 clang/lib/AST/ASTContext.cpp                  | 50 +++++++++++++++++++
 clang/lib/AST/ASTImporter.cpp                 |  9 ++++
 clang/lib/AST/ASTStructuralEquivalence.cpp    |  6 +++
 clang/lib/AST/ExprConstant.cpp                |  1 +
 clang/lib/AST/ItaniumMangle.cpp               |  8 +++
 clang/lib/AST/MicrosoftMangle.cpp             | 14 ++++++
 clang/lib/AST/ODRHash.cpp                     |  5 ++
 clang/lib/AST/Type.cpp                        |  6 +++
 clang/lib/AST/TypePrinter.cpp                 | 14 ++++++
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |  5 ++
 clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp |  6 +++
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp         |  9 ++++
 clang/lib/CodeGen/CGDebugInfo.cpp             |  7 +++
 clang/lib/CodeGen/CGDebugInfo.h               |  1 +
 clang/lib/CodeGen/CodeGenFunction.cpp         |  2 +
 clang/lib/CodeGen/CodeGenTypes.cpp            |  8 +++
 clang/lib/CodeGen/ItaniumCXXABI.cpp           |  6 +++
 clang/lib/CodeGen/QualTypeMapper.cpp          |  6 +++
 clang/lib/Sema/SemaExpr.cpp                   |  1 +
 clang/lib/Sema/SemaLookup.cpp                 |  1 +
 clang/lib/Sema/SemaTemplate.cpp               |  5 ++
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  2 +
 clang/lib/Sema/TreeTransform.h                | 33 ++++++++++++
 clang/lib/Serialization/ASTReader.cpp         |  4 ++
 clang/lib/Serialization/ASTWriter.cpp         |  3 ++
 clang/tools/libclang/CIndex.cpp               |  4 ++
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  6 +++
 34 files changed, 302 insertions(+)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index a4ed852d36442..e478f47110ce4 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -291,6 +291,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
   mutable llvm::ContextualFoldingSet<AttributedType, ASTContext &>
       AttributedTypes;
   mutable llvm::FoldingSet<PipeType> PipeTypes;
+  mutable llvm::FoldingSet<WebAssemblyTableType> WebAssemblyTableTypes;
   mutable llvm::FoldingSet<BitIntType> BitIntTypes;
   mutable llvm::ContextualFoldingSet<DependentBitIntType, ASTContext &>
       DependentBitIntTypes;
@@ -1671,6 +1672,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// Return a write_only pipe type for the specified type.
   QualType getWritePipeType(QualType T) const;
 
+  /// Return a WebAssembly table type with the specified element type (a
+  /// WebAssembly reference type).
+  QualType getWebAssemblyTableType(QualType T) const;
+
   /// Return a bit-precise integer type with the specified signedness and bit
   /// count.
   QualType getBitIntType(bool Unsigned, unsigned NumBits) const;
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index b000a34043696..4ed5ac7040bb4 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1250,6 +1250,9 @@ DEF_TRAVERSE_TYPE(AtomicType, { 
TRY_TO(TraverseType(T->getValueType())); })
 
 DEF_TRAVERSE_TYPE(PipeType, { TRY_TO(TraverseType(T->getElementType())); })
 
+DEF_TRAVERSE_TYPE(WebAssemblyTableType,
+                  { TRY_TO(TraverseType(T->getElementType())); })
+
 DEF_TRAVERSE_TYPE(BitIntType, {})
 DEF_TRAVERSE_TYPE(DependentBitIntType,
                   { TRY_TO(TraverseStmt(T->getNumBitsExpr())); })
@@ -1614,6 +1617,9 @@ DEF_TRAVERSE_TYPELOC(AtomicType, { 
TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
 
 DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
 
+DEF_TRAVERSE_TYPELOC(WebAssemblyTableType,
+                     { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
+
 DEF_TRAVERSE_TYPELOC(BitIntType, {})
 DEF_TRAVERSE_TYPELOC(DependentBitIntType, {
   TRY_TO(TraverseStmt(TL.getTypePtr()->getNumBitsExpr()));
diff --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index 3a801e2857b13..493a5242581ef 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -8295,6 +8295,40 @@ class PipeType : public Type, public 
llvm::FoldingSetNode {
   bool isReadOnly() const { return isRead; }
 };
 
+/// WebAssemblyTableType - declared via `static __externref_t table[];`.
+///
+/// These correspond to llvm_table_ty in llvm ir and tableidx immediates in 
llvm
+/// ir. Because a tableidx is an immediate, these are not really values at all.
+/// All values of this type must be global variables and they cannot be used
+/// anywhere other than arguments to wasm table builtins like
+/// __builtin_wasm_table_get().
+class WebAssemblyTableType : public Type, public llvm::FoldingSetNode {
+  friend class ASTContext; // ASTContext creates these.
+
+  QualType ElementType;
+
+  WebAssemblyTableType(QualType elemType, QualType CanonicalPtr)
+      : Type(WebAssemblyTable, CanonicalPtr, elemType->getDependence()),
+        ElementType(elemType) {}
+
+public:
+  QualType getElementType() const { return ElementType; }
+
+  bool isSugared() const { return false; }
+
+  QualType desugar() const { return QualType(this, 0); }
+
+  void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType()); }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
+    ID.AddPointer(T.getAsOpaquePtr());
+  }
+
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == WebAssemblyTable;
+  }
+};
+
 /// A fixed int type of a specified bitwidth.
 class BitIntType final : public Type, public llvm::FoldingSetNode {
   friend class ASTContext;
diff --git a/clang/include/clang/AST/TypeLoc.h 
b/clang/include/clang/AST/TypeLoc.h
index 24df18dbaace4..9893ff49ee6a0 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -2731,6 +2731,29 @@ class PipeTypeLoc : public 
ConcreteTypeLoc<UnqualTypeLoc, PipeTypeLoc, PipeType,
   QualType getInnerType() const { return this->getTypePtr()->getElementType(); 
}
 };
 
+struct WebAssemblyTableTypeLocInfo {
+  SourceLocation KWLoc;
+};
+
+class WebAssemblyTableTypeLoc
+    : public ConcreteTypeLoc<UnqualTypeLoc, WebAssemblyTableTypeLoc,
+                             WebAssemblyTableType,
+                             WebAssemblyTableTypeLocInfo> {
+public:
+  TypeLoc getValueLoc() const { return this->getInnerTypeLoc(); }
+
+  SourceRange getLocalSourceRange() const { return SourceRange(getKWLoc()); }
+
+  SourceLocation getKWLoc() const { return this->getLocalData()->KWLoc; }
+  void setKWLoc(SourceLocation Loc) { this->getLocalData()->KWLoc = Loc; }
+
+  void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+    setKWLoc(Loc);
+  }
+
+  QualType getInnerType() const { return this->getTypePtr()->getElementType(); 
}
+};
+
 template <typename T>
 inline T TypeLoc::getAsAdjusted() const {
   TypeLoc Cur = *this;
diff --git a/clang/include/clang/AST/TypeProperties.td 
b/clang/include/clang/AST/TypeProperties.td
index f16c10da430f9..891a046cb31c3 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -967,6 +967,16 @@ let Class = PipeType in {
   }]>;
 }
 
+let Class = WebAssemblyTableType in {
+  def : Property<"elementType", QualType> {
+    let Read = [{ node->getElementType() }];
+  }
+
+  def : Creator<[{
+    return ctx.getWebAssemblyTableType(elementType);
+  }]>;
+}
+
 let Class = BitIntType in {
   def : Property<"isUnsigned", Bool> {
     let Read = [{ node->isUnsigned() }];
diff --git a/clang/include/clang/Basic/TypeNodes.td 
b/clang/include/clang/Basic/TypeNodes.td
index a9965a4a89aa1..b61440f244670 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -106,6 +106,7 @@ def ObjCObjectPointerType : TypeNode<Type>;
 def BoundsAttributedType : TypeNode<Type, 1>;
 def CountAttributedType : TypeNode<BoundsAttributedType>, NeverCanonical;
 def PipeType : TypeNode<Type>;
+def WebAssemblyTableType : TypeNode<Type>;
 def AtomicType : TypeNode<Type>;
 def BitIntType : TypeNode<Type>;
 def DependentBitIntType : TypeNode<Type>, AlwaysDependent;
diff --git a/clang/include/clang/Serialization/TypeBitCodes.def 
b/clang/include/clang/Serialization/TypeBitCodes.def
index 9f1da65e0f940..8b66cd1e3cadb 100644
--- a/clang/include/clang/Serialization/TypeBitCodes.def
+++ b/clang/include/clang/Serialization/TypeBitCodes.def
@@ -70,5 +70,6 @@ TYPE_BIT_CODE(HLSLInlineSpirv, HLSL_INLINE_SPIRV, 60)
 TYPE_BIT_CODE(PredefinedSugar, PREDEFINED_SUGAR, 61)
 TYPE_BIT_CODE(SubstBuiltinTemplatePack, SUBST_BUILTIN_TEMPLATE_PACK, 62)
 TYPE_BIT_CODE(OverflowBehavior, OVERFLOWBEHAVIOR, 63)
+TYPE_BIT_CODE(WebAssemblyTable, WEBASSEMBLY_TABLE, 64)
 
 #undef TYPE_BIT_CODE
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index abf0cd5e18c2b..a6722fde583c4 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2638,6 +2638,15 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) 
const {
     Width = Target->getPointerWidth(LangAS::opencl_global);
     Align = Target->getPointerAlign(LangAS::opencl_global);
     break;
+
+  case Type::WebAssemblyTable: {
+    // A WebAssembly table is a zero-length array of a reference type; it has
+    // no storage size and takes the alignment of its element type.
+    const auto *WTT = cast<WebAssemblyTableType>(T);
+    Width = 0;
+    Align = getTypeAlign(WTT->getElementType());
+    break;
+  }
   }
 
   assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2");
@@ -3493,6 +3502,7 @@ static void encodeTypeForFunctionPointerAuth(const 
ASTContext &Ctx,
 
   // Don't bother discriminating based on these types.
   case Type::Pipe:
+  case Type::WebAssemblyTable:
   case Type::BitInt:
   case Type::ConstantMatrix:
     OS << "?";
@@ -4343,6 +4353,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType 
type) const {
   case Type::HLSLAttributedResource:
   case Type::HLSLInlineSpirv:
   case Type::OverflowBehavior:
+  case Type::WebAssemblyTable:
     llvm_unreachable("type should never be variably-modified");
 
   // These types can be variably-modified but should never need to
@@ -5222,6 +5233,34 @@ QualType ASTContext::getWritePipeType(QualType T) const {
   return getPipeType(T, false);
 }
 
+QualType ASTContext::getWebAssemblyTableType(QualType T) const {
+  llvm::FoldingSetNodeID ID;
+  WebAssemblyTableType::Profile(ID, T);
+
+  void *InsertPos = nullptr;
+  if (WebAssemblyTableType *WTT =
+          WebAssemblyTableTypes.FindNodeOrInsertPos(ID, InsertPos))
+    return QualType(WTT, 0);
+
+  // If the element type isn't canonical, this won't be a canonical type 
either,
+  // so fill in the canonical type field.
+  QualType Canonical;
+  if (!T.isCanonical()) {
+    Canonical = getWebAssemblyTableType(getCanonicalType(T));
+
+    // Get the new insert position for the node we care about.
+    WebAssemblyTableType *NewIP =
+        WebAssemblyTableTypes.FindNodeOrInsertPos(ID, InsertPos);
+    assert(!NewIP && "Shouldn't be in the map!");
+    (void)NewIP;
+  }
+  auto *New = new (*this, alignof(WebAssemblyTableType))
+      WebAssemblyTableType(T, Canonical);
+  Types.push_back(New);
+  WebAssemblyTableTypes.InsertNode(New, InsertPos);
+  return QualType(New, 0);
+}
+
 QualType ASTContext::getBitIntType(bool IsUnsigned, unsigned NumBits) const {
   llvm::FoldingSetNodeID ID;
   BitIntType::Profile(ID, IsUnsigned, NumBits);
@@ -9758,6 +9797,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, 
std::string &S,
 
   case Type::ArrayParameter:
   case Type::Pipe:
+  case Type::WebAssemblyTable:
 #define ABSTRACT_TYPE(KIND, BASE)
 #define TYPE(KIND, BASE)
 #define DEPENDENT_TYPE(KIND, BASE) \
@@ -12208,6 +12248,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType 
RHS, bool OfBlockPointer,
     assert(LHS != RHS &&
            "Equivalent pipe types should have already been handled!");
     return {};
+  case Type::WebAssemblyTable:
+    assert(LHS != RHS && "Equivalent WebAssembly table types should have "
+                         "already been handled!");
+    return {};
   case Type::ArrayParameter:
     assert(LHS != RHS &&
            "Equivalent ArrayParameter types should have already been 
handled!");
@@ -14662,6 +14706,11 @@ static QualType getCommonNonSugarTypeNode(const 
ASTContext &Ctx, const Type *X,
                                : &ASTContext::getWritePipeType;
     return (Ctx.*MP)(getCommonElementType(Ctx, PX, PY));
   }
+  case Type::WebAssemblyTable: {
+    const auto *TX = cast<WebAssemblyTableType>(X),
+               *TY = cast<WebAssemblyTableType>(Y);
+    return Ctx.getWebAssemblyTableType(getCommonElementType(Ctx, TX, TY));
+  }
   case Type::TemplateTypeParm: {
     const auto *TX = cast<TemplateTypeParmType>(X),
                *TY = cast<TemplateTypeParmType>(Y);
@@ -14717,6 +14766,7 @@ static QualType getCommonSugarTypeNode(const ASTContext 
&Ctx, const Type *X,
     CANONICAL_TYPE(RValueReference)
     CANONICAL_TYPE(VariableArray)
     CANONICAL_TYPE(Vector)
+    CANONICAL_TYPE(WebAssemblyTable)
 #undef CANONICAL_TYPE
 
 #undef UNEXPECTED_TYPE
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 567d2d07298a3..f53e9934930e6 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -2172,6 +2172,15 @@ ExpectedType clang::ASTNodeImporter::VisitPipeType(const 
clang::PipeType *T) {
     return ToCtx.getWritePipeType(*ToElementTypeOrErr);
 }
 
+ExpectedType clang::ASTNodeImporter::VisitWebAssemblyTableType(
+    const clang::WebAssemblyTableType *T) {
+  ExpectedType ToElementTypeOrErr = import(T->getElementType());
+  if (!ToElementTypeOrErr)
+    return ToElementTypeOrErr.takeError();
+
+  return Importer.getToContext().getWebAssemblyTableType(*ToElementTypeOrErr);
+}
+
 //----------------------------------------------------------------------------
 // Import Declarations
 //----------------------------------------------------------------------------
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp 
b/clang/lib/AST/ASTStructuralEquivalence.cpp
index e0b62591a6a73..6be798a8aa37b 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1528,6 +1528,12 @@ bool ASTStructuralEquivalence::isEquivalent(
                                   cast<PipeType>(T2)->getElementType()))
       return false;
     break;
+  case Type::WebAssemblyTable:
+    if (!IsStructurallyEquivalent(
+            Context, cast<WebAssemblyTableType>(T1)->getElementType(),
+            cast<WebAssemblyTableType>(T2)->getElementType()))
+      return false;
+    break;
   case Type::BitInt: {
     const auto *Int1 = cast<BitIntType>(T1);
     const auto *Int2 = cast<BitIntType>(T2);
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 28ac44edd800c..fd018ed266c00 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15988,6 +15988,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
   case Type::ObjCInterface:
   case Type::ObjCObjectPointer:
   case Type::Pipe:
+  case Type::WebAssemblyTable:
   case Type::HLSLAttributedResource:
   case Type::HLSLInlineSpirv:
   case Type::OverflowBehavior:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index e5cdd6f31c507..287075c8f64f7 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2468,6 +2468,7 @@ bool 
CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
   case Type::ObjCTypeParam:
   case Type::Atomic:
   case Type::Pipe:
+  case Type::WebAssemblyTable:
   case Type::MacroQualified:
   case Type::BitInt:
   case Type::DependentBitInt:
@@ -4622,6 +4623,13 @@ void CXXNameMangler::mangleType(const PipeType *T) {
   Out << "8ocl_pipe";
 }
 
+void CXXNameMangler::mangleType(const WebAssemblyTableType *T) {
+  // Vendor-extended type mangling for WebAssembly tables.
+  // <type> ::= u9wasmtable <element-type>
+  Out << "u9wasmtable";
+  mangleType(T->getElementType());
+}
+
 void CXXNameMangler::mangleType(const OverflowBehaviorType *T) {
   // Vender-extended type mangling for OverflowBehaviorType
   // <type> ::= U <behavior> <underlying_type>
diff --git a/clang/lib/AST/MicrosoftMangle.cpp 
b/clang/lib/AST/MicrosoftMangle.cpp
index adfe260a0d091..5e4ef6b4ad47c 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -3928,6 +3928,20 @@ void MicrosoftCXXNameMangler::mangleType(const PipeType 
*T, Qualifiers,
   mangleArtificialTagType(TagTypeKind::Struct, TemplateMangling, {"__clang"});
 }
 
+void MicrosoftCXXNameMangler::mangleType(const WebAssemblyTableType *T,
+                                         Qualifiers, SourceRange Range) {
+  QualType ElementType = T->getElementType();
+
+  llvm::SmallString<64> TemplateMangling;
+  llvm::raw_svector_ostream Stream(TemplateMangling);
+  MicrosoftCXXNameMangler Extra(Context, Stream);
+  Stream << "?$";
+  Extra.mangleSourceName("wasmtable");
+  Extra.mangleType(ElementType, Range, QMM_Escape);
+
+  mangleArtificialTagType(TagTypeKind::Struct, TemplateMangling, {"__clang"});
+}
+
 void MicrosoftMangleContextImpl::mangleCXXName(GlobalDecl GD,
                                                raw_ostream &Out) {
   const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 46a4e256ea3e5..62537c18ccb5e 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -1126,6 +1126,11 @@ class ODRTypeVisitor : public 
TypeVisitor<ODRTypeVisitor> {
     VisitType(T);
   }
 
+  void VisitWebAssemblyTableType(const WebAssemblyTableType *T) {
+    AddQualType(T->getElementType());
+    VisitType(T);
+  }
+
   void VisitPointerType(const PointerType *T) {
     AddQualType(T->getPointeeType());
     VisitType(T);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index dffb3f1b50207..329abcceb2c98 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5011,6 +5011,8 @@ static CachedProperties computeCachedProperties(const 
Type *T) {
     return Cache::get(cast<AtomicType>(T)->getValueType());
   case Type::Pipe:
     return Cache::get(cast<PipeType>(T)->getElementType());
+  case Type::WebAssemblyTable:
+    return Cache::get(cast<WebAssemblyTableType>(T)->getElementType());
   case Type::HLSLAttributedResource:
     return Cache::get(cast<HLSLAttributedResourceType>(T)->getWrappedType());
   case Type::HLSLInlineSpirv:
@@ -5112,6 +5114,9 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const 
Type *T) {
     return computeTypeLinkageInfo(cast<AtomicType>(T)->getValueType());
   case Type::Pipe:
     return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
+  case Type::WebAssemblyTable:
+    return computeTypeLinkageInfo(
+        cast<WebAssemblyTableType>(T)->getElementType());
   case Type::OverflowBehavior:
     return computeTypeLinkageInfo(
         cast<OverflowBehaviorType>(T)->getUnderlyingType());
@@ -5304,6 +5309,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const 
{
   case Type::ObjCInterface:
   case Type::Atomic:
   case Type::Pipe:
+  case Type::WebAssemblyTable:
   case Type::BitInt:
   case Type::DependentBitInt:
   case Type::ArrayParameter:
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index e8fbffb9f954d..e1ae5612286a6 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -240,6 +240,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
     case Type::ObjCInterface:
     case Type::Atomic:
     case Type::Pipe:
+    case Type::WebAssemblyTable:
     case Type::BitInt:
     case Type::DependentBitInt:
     case Type::BTFTagAttributed:
@@ -1520,6 +1521,19 @@ void TypePrinter::printPipeBefore(const PipeType *T, 
raw_ostream &OS) {
 
 void TypePrinter::printPipeAfter(const PipeType *T, raw_ostream &OS) {}
 
+void TypePrinter::printWebAssemblyTableBefore(const WebAssemblyTableType *T,
+                                              raw_ostream &OS) {
+  IncludeStrongLifetimeRAII Strong(Policy);
+  printBefore(T->getElementType(), OS);
+}
+
+void TypePrinter::printWebAssemblyTableAfter(const WebAssemblyTableType *T,
+                                             raw_ostream &OS) {
+  // Print like the zero-length array a table is declared as.
+  OS << "[0]";
+  printAfter(T->getElementType(), OS);
+}
+
 void TypePrinter::printBitIntBefore(const BitIntType *T, raw_ostream &OS) {
   if (T->isUnsigned())
     OS << "unsigned ";
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 6606cf74c7dea..4b957167f31a2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -86,6 +86,7 @@ cir::TypeEvaluationKind 
CIRGenFunction::getEvaluationKind(QualType type) {
     case Type::ObjCObject:
     case Type::ObjCInterface:
     case Type::ArrayParameter:
+    case Type::WebAssemblyTable:
       return cir::TEK_Aggregate;
 
     // We operate on atomic values according to their underlying type.
@@ -1770,6 +1771,10 @@ void CIRGenFunction::emitVariablyModifiedType(QualType 
type) {
     case Type::Pipe:
       type = cast<clang::PipeType>(ty)->getElementType();
       break;
+
+    case Type::WebAssemblyTable:
+      type = cast<clang::WebAssemblyTableType>(ty)->getElementType();
+      break;
     }
   } while (type->isVariablyModifiedType());
 }
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp 
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 552d73966e97b..5550dc5437172 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -1029,6 +1029,9 @@ const char *vTableClassNameForType(const CIRGenModule 
&cgm, const Type *ty) {
   case Type::Pipe:
     llvm_unreachable("Pipe types shouldn't get here");
 
+  case Type::WebAssemblyTable:
+    llvm_unreachable("WebAssembly table types shouldn't get here");
+
   case Type::ArrayParameter:
     llvm_unreachable("Array Parameter types should not get here.");
 
@@ -1522,6 +1525,9 @@ mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
   case Type::Pipe:
     break;
 
+  case Type::WebAssemblyTable:
+    break;
+
   case Type::BitInt:
     break;
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 3170666304a06..370328954d59b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -586,6 +586,15 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
     break;
   }
 
+  case Type::WebAssemblyTable: {
+    // A WebAssembly table lowers to a zero-length array of its (reference 
type)
+    // element, matching the classic codegen lowering.
+    const auto *wtt = cast<WebAssemblyTableType>(ty);
+    mlir::Type elemTy = convertTypeForMem(wtt->getElementType());
+    resultType = cir::ArrayType::get(elemTy, 0);
+    break;
+  }
+
   case Type::ExtVector:
   case Type::Vector: {
     const VectorType *vec = cast<VectorType>(ty);
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 7421733efcc24..9de1d3899bb36 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -3974,6 +3974,11 @@ llvm::DIType *CGDebugInfo::CreateType(const PipeType 
*Ty, llvm::DIFile *U) {
   return getOrCreateType(Ty->getElementType(), U);
 }
 
+llvm::DIType *CGDebugInfo::CreateType(const WebAssemblyTableType *Ty,
+                                      llvm::DIFile *U) {
+  return getOrCreateType(Ty->getElementType(), U);
+}
+
 llvm::DIType *CGDebugInfo::CreateType(const HLSLAttributedResourceType *Ty,
                                       llvm::DIFile *U) {
   return getOrCreateType(Ty->getWrappedType(), U);
@@ -4342,6 +4347,8 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, 
llvm::DIFile *Unit) {
     return CreateType(cast<OverflowBehaviorType>(Ty), Unit);
   case Type::Pipe:
     return CreateType(cast<PipeType>(Ty), Unit);
+  case Type::WebAssemblyTable:
+    return CreateType(cast<WebAssemblyTableType>(Ty), Unit);
 
   case Type::TemplateSpecialization:
     return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index a818d6471ff3e..5f884139b70e0 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -245,6 +245,7 @@ class CGDebugInfo {
   llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F);
   llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F);
   llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F);
+  llvm::DIType *CreateType(const WebAssemblyTableType *Ty, llvm::DIFile *F);
   /// Get enumeration type.
   llvm::DIType *CreateEnumType(const EnumType *Ty);
   llvm::DIType *CreateTypeDefinition(const EnumType *Ty);
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
index b920266b59808..4201f8f536805 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -292,6 +292,7 @@ TypeEvaluationKind 
CodeGenFunction::getEvaluationKind(QualType type) {
     case Type::ObjCObject:
     case Type::ObjCInterface:
     case Type::ArrayParameter:
+    case Type::WebAssemblyTable:
       return TEK_Aggregate;
 
     // We operate on atomic values according to their underlying type.
@@ -2569,6 +2570,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType 
type) {
     case Type::BitInt:
     case Type::HLSLInlineSpirv:
     case Type::PredefinedSugar:
+    case Type::WebAssemblyTable:
       llvm_unreachable("type class is never variably-modified!");
 
     case Type::Adjusted:
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp 
b/clang/lib/CodeGen/CodeGenTypes.cpp
index 3de3bad6affb5..66f31863b3ffb 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -796,6 +796,14 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
     ResultType = CGM.getOpenCLRuntime().getPipeType(cast<PipeType>(Ty));
     break;
   }
+  case Type::WebAssemblyTable: {
+    // A WebAssembly table lowers to a zero-length array of its (reference 
type)
+    // element, matching the classic array-based lowering.
+    const auto *WTT = cast<WebAssemblyTableType>(Ty);
+    llvm::Type *EltTy = ConvertTypeForMem(WTT->getElementType());
+    ResultType = llvm::ArrayType::get(EltTy, 0);
+    break;
+  }
   case Type::BitInt: {
     const auto &EIT = cast<BitIntType>(Ty);
     ResultType = llvm::Type::getIntNTy(getLLVMContext(), EIT->getNumBits());
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index b4b3284f752ae..c6d6b675a1b6f 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3997,6 +3997,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type 
*Ty,
   case Type::Pipe:
     llvm_unreachable("Pipe types shouldn't get here");
 
+  case Type::WebAssemblyTable:
+    llvm_unreachable("WebAssembly table types shouldn't get here");
+
   case Type::ArrayParameter:
     llvm_unreachable("Array Parameter types should not get here.");
 
@@ -4297,6 +4300,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
   case Type::Pipe:
     break;
 
+  case Type::WebAssemblyTable:
+    break;
+
   case Type::BitInt:
     break;
 
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp 
b/clang/lib/CodeGen/QualTypeMapper.cpp
index 31d9250a48ec9..d5d38f0ebd8b1 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -102,6 +102,12 @@ const llvm::abi::Type 
*QualTypeMapper::convertTypeImpl(QualType QT) {
   case Type::BlockPointer:
   case Type::Pipe:
     return createPointerTypeForPointee(ASTCtx.VoidPtrTy);
+  case Type::WebAssemblyTable: {
+    // A WebAssembly table is a zero-length array of its element type.
+    const auto *WTT = cast<WebAssemblyTableType>(QT);
+    return Builder.getArrayType(convertType(WTT->getElementType()),
+                                /*NumElements=*/0, /*Size=*/0);
+  }
   case Type::ConstantMatrix: {
     const auto *MT = cast<ConstantMatrixType>(QT);
     return Builder.getArrayType(convertType(MT->getElementType()),
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7c868d176e803..b447eae2cee36 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4615,6 +4615,7 @@ static void captureVariablyModifiedType(ASTContext 
&Context, QualType T,
     case Type::ObjCObjectPointer:
     case Type::ObjCTypeParam:
     case Type::Pipe:
+    case Type::WebAssemblyTable:
     case Type::BitInt:
     case Type::HLSLInlineSpirv:
       llvm_unreachable("type class is never variably-modified!");
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 65b60964d1192..ef6dc80608d9c 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3294,6 +3294,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup 
&Result, QualType Ty) {
 
     // Array parameter types are treated as fundamental types.
     case Type::ArrayParameter:
+    case Type::WebAssemblyTable:
       break;
 
     case Type::HLSLAttributedResource:
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 556fa716d61e7..11b02d3e88dfd 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6464,6 +6464,11 @@ bool UnnamedLocalNoLinkageFinder::VisitPipeType(const 
PipeType* T) {
   return false;
 }
 
+bool UnnamedLocalNoLinkageFinder::VisitWebAssemblyTableType(
+    const WebAssemblyTableType *T) {
+  return Visit(T->getElementType());
+}
+
 bool UnnamedLocalNoLinkageFinder::VisitBitIntType(const BitIntType *T) {
   return false;
 }
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 26c397afdd6ef..9a18bedcb6e97 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2539,6 +2539,7 @@ static TemplateDeductionResult 
DeduceTemplateArgumentsByTypeMatch(
     case Type::DeducedTemplateSpecialization:
     case Type::PackExpansion:
     case Type::Pipe:
+    case Type::WebAssemblyTable:
     case Type::ArrayParameter:
     case Type::HLSLAttributedResource:
     case Type::HLSLInlineSpirv:
@@ -7066,6 +7067,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
   case Type::ObjCObjectPointer:
   case Type::UnresolvedUsing:
   case Type::Pipe:
+  case Type::WebAssemblyTable:
   case Type::BitInt:
   case Type::HLSLInlineSpirv:
   case Type::OverflowBehavior:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3b99ff4bb9e23..c90bfde84a9ca 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1289,6 +1289,10 @@ class TreeTransform {
   QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc,
                            bool isReadPipe);
 
+  /// Build a new WebAssembly table type given its element type.
+  QualType RebuildWebAssemblyTableType(QualType ElementType,
+                                       SourceLocation KWLoc);
+
   /// Build a bit-precise int given its value type.
   QualType RebuildBitIntType(bool IsUnsigned, unsigned NumBits,
                              SourceLocation Loc);
@@ -7424,6 +7428,28 @@ QualType 
TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
   return Result;
 }
 
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformWebAssemblyTableType(
+    TypeLocBuilder &TLB, WebAssemblyTableTypeLoc TL) {
+  QualType ElementType = getDerived().TransformType(TLB, TL.getValueLoc());
+  if (ElementType.isNull())
+    return QualType();
+
+  QualType Result = TL.getType();
+  if (getDerived().AlwaysRebuild() ||
+      ElementType != TL.getValueLoc().getType()) {
+    Result =
+        getDerived().RebuildWebAssemblyTableType(ElementType, TL.getKWLoc());
+    if (Result.isNull())
+      return QualType();
+  }
+
+  WebAssemblyTableTypeLoc NewTL = TLB.push<WebAssemblyTableTypeLoc>(Result);
+  NewTL.setKWLoc(TL.getKWLoc());
+
+  return Result;
+}
+
 template <typename Derived>
 QualType TreeTransform<Derived>::TransformBitIntType(TypeLocBuilder &TLB,
                                                      BitIntTypeLoc TL) {
@@ -17863,6 +17889,13 @@ QualType 
TreeTransform<Derived>::RebuildPipeType(QualType ValueType,
                     : SemaRef.BuildWritePipeType(ValueType, KWLoc);
 }
 
+template <typename Derived>
+QualType
+TreeTransform<Derived>::RebuildWebAssemblyTableType(QualType ElementType,
+                                                    SourceLocation KWLoc) {
+  return SemaRef.Context.getWebAssemblyTableType(ElementType);
+}
+
 template <typename Derived>
 QualType TreeTransform<Derived>::RebuildBitIntType(bool IsUnsigned,
                                                    unsigned NumBits,
diff --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index f8a6a38bb9b5c..9013aa94d76a5 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7808,6 +7808,10 @@ void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) {
   TL.setKWLoc(readSourceLocation());
 }
 
+void TypeLocReader::VisitWebAssemblyTableTypeLoc(WebAssemblyTableTypeLoc TL) {
+  TL.setKWLoc(readSourceLocation());
+}
+
 void TypeLocReader::VisitBitIntTypeLoc(clang::BitIntTypeLoc TL) {
   TL.setNameLoc(readSourceLocation());
 }
diff --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index 357a7f7e95fa0..77632d4e65030 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -684,6 +684,9 @@ void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
 void TypeLocWriter::VisitPipeTypeLoc(PipeTypeLoc TL) {
   addSourceLocation(TL.getKWLoc());
 }
+void TypeLocWriter::VisitWebAssemblyTableTypeLoc(WebAssemblyTableTypeLoc TL) {
+  addSourceLocation(TL.getKWLoc());
+}
 void TypeLocWriter::VisitBitIntTypeLoc(clang::BitIntTypeLoc TL) {
   addSourceLocation(TL.getNameLoc());
 }
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index ac2fad38a1348..feed6197c68e6 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1876,6 +1876,10 @@ bool CursorVisitor::VisitPipeTypeLoc(PipeTypeLoc TL) {
   return Visit(TL.getValueLoc());
 }
 
+bool CursorVisitor::VisitWebAssemblyTableTypeLoc(WebAssemblyTableTypeLoc TL) {
+  return Visit(TL.getValueLoc());
+}
+
 #define DEFAULT_TYPELOC_IMPL(CLASS, PARENT)                                    
\
   bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) {               
\
     return Visit##PARENT##Loc(TL);                                             
\
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 82fd9844cf96a..952a2155f23a0 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -4219,6 +4219,8 @@ 
TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) {
     break;
   case clang::Type::SubstBuiltinTemplatePack:
     break;
+  case clang::Type::WebAssemblyTable:
+    break;
   }
   // We don't know hot to display this type...
   return lldb::eTypeClassOther;
@@ -5082,6 +5084,8 @@ lldb::Encoding 
TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type) {
     break;
   case clang::Type::SubstBuiltinTemplatePack:
     break;
+  case clang::Type::WebAssemblyTable:
+    break;
   }
 
   return lldb::eEncodingInvalid;
@@ -5252,6 +5256,8 @@ lldb::Format 
TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) {
     break;
   case clang::Type::SubstBuiltinTemplatePack:
     break;
+  case clang::Type::WebAssemblyTable:
+    break;
   }
   // We don't know hot to display this type...
   return lldb::eFormatBytes;

>From 5f547ad3e0b84c0f5719ef4e906ccb84f999b1ab Mon Sep 17 00:00:00 2001
From: Hood Chatham <[email protected]>
Date: Thu, 4 Jun 2026 17:02:32 -0700
Subject: [PATCH 2/2] Use new WebAssemblyTableType in codegen

---
 clang/include/clang/Sema/SemaInternal.h       | 13 +++++
 clang/lib/AST/Expr.cpp                        |  5 ++
 clang/lib/AST/Type.cpp                        |  8 +--
 .../CodeGen/TargetBuiltins/WebAssembly.cpp    | 26 ++++-----
 clang/lib/Sema/SemaDecl.cpp                   | 55 +++++++++++--------
 clang/lib/Sema/SemaExpr.cpp                   | 13 +++--
 clang/lib/Sema/SemaExprCXX.cpp                | 12 ++--
 clang/lib/Sema/SemaInit.cpp                   |  9 +++
 clang/lib/Sema/SemaStmt.cpp                   | 11 ++--
 clang/lib/Sema/SemaType.cpp                   | 32 +++++++++--
 clang/lib/Sema/SemaWasm.cpp                   |  6 +-
 clang/test/Sema/wasm-refs-and-tables.c        |  6 +-
 clang/test/SemaCXX/wasm-refs-and-tables.cpp   |  2 +-
 13 files changed, 129 insertions(+), 69 deletions(-)

diff --git a/clang/include/clang/Sema/SemaInternal.h 
b/clang/include/clang/Sema/SemaInternal.h
index 8f6041b5f00e4..f847d98d6c162 100644
--- a/clang/include/clang/Sema/SemaInternal.h
+++ b/clang/include/clang/Sema/SemaInternal.h
@@ -35,6 +35,19 @@ FTIHasNonVoidParameters(const 
DeclaratorChunk::FunctionTypeInfo &FTI) {
   return FTI.NumParams && !FTIHasSingleVoidParameter(FTI);
 }
 
+/// Determine whether \p T is a WebAssembly table. A valid table is represented
+/// by a WebAssemblyTableType; an array of a WebAssembly reference type that is
+/// not a valid table (e.g. has a non-zero or unspecified length) remains an
+/// ArrayType and is matched here so that it can be diagnosed.
+inline bool isWebAssemblyTableOrRefArrayType(const ASTContext &Ctx,
+                                             QualType T) {
+  if (T->isWebAssemblyTableType())
+    return true;
+  if (const auto *ATy = Ctx.getAsArrayType(T))
+    return ATy->getElementType().isWebAssemblyReferenceType();
+  return false;
+}
+
 // Helper function to check whether D's attributes match current CUDA mode.
 // Decls with mismatched attributes and related diagnostics may have to be
 // ignored during this CUDA compilation pass.
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 1bafc4708a30b..0b01a24ae79ab 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3444,6 +3444,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool 
IsForRef,
       return true;
     }
 
+    // A WebAssembly table is a zero-length aggregate; an initializer
+    // list for it must be empty so is always constant.
+    if (ILE->getType()->isWebAssemblyTableType())
+      return true;
+
     if (ILE->getType()->isRecordType()) {
       unsigned ElementNo = 0;
       auto *RD = ILE->getType()->castAsRecordDecl();
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 329abcceb2c98..a0315e1eb5386 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2649,13 +2649,7 @@ bool Type::isWebAssemblyExternrefType() const {
 }
 
 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;
+  return isa<WebAssemblyTableType>(CanonicalType);
 }
 
 bool Type::isSizelessType() const { return isSizelessBuiltinType(); }
diff --git a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp 
b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
index e7bdb91d49ce8..217a643469773 100644
--- a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
@@ -589,8 +589,8 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned 
BuiltinID,
     return Builder.CreateCall(Callee, {Vector, Index, Val});
   }
   case WebAssembly::BI__builtin_wasm_table_get: {
-    assert(E->getArg(0)->getType()->isArrayType());
-    Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
+    assert(E->getArg(0)->getType()->isWebAssemblyTableType());
+    Value *Table = EmitLValue(E->getArg(0)).emitRawPointer(*this);
     Value *Index = EmitScalarExpr(E->getArg(1));
     Function *Callee;
     if (E->getType().isWebAssemblyExternrefType())
@@ -603,8 +603,8 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned 
BuiltinID,
     return Builder.CreateCall(Callee, {Table, Index});
   }
   case WebAssembly::BI__builtin_wasm_table_set: {
-    assert(E->getArg(0)->getType()->isArrayType());
-    Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
+    assert(E->getArg(0)->getType()->isWebAssemblyTableType());
+    Value *Table = EmitLValue(E->getArg(0)).emitRawPointer(*this);
     Value *Index = EmitScalarExpr(E->getArg(1));
     Value *Val = EmitScalarExpr(E->getArg(2));
     Function *Callee;
@@ -618,14 +618,14 @@ Value 
*CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
     return Builder.CreateCall(Callee, {Table, Index, Val});
   }
   case WebAssembly::BI__builtin_wasm_table_size: {
-    assert(E->getArg(0)->getType()->isArrayType());
-    Value *Value = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
+    assert(E->getArg(0)->getType()->isWebAssemblyTableType());
+    Value *Value = EmitLValue(E->getArg(0)).emitRawPointer(*this);
     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 = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
+    assert(E->getArg(0)->getType()->isWebAssemblyTableType());
+    Value *Table = EmitLValue(E->getArg(0)).emitRawPointer(*this);
     Value *Val = EmitScalarExpr(E->getArg(1));
     Value *NElems = EmitScalarExpr(E->getArg(2));
 
@@ -641,8 +641,8 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned 
BuiltinID,
     return Builder.CreateCall(Callee, {Table, Val, NElems});
   }
   case WebAssembly::BI__builtin_wasm_table_fill: {
-    assert(E->getArg(0)->getType()->isArrayType());
-    Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
+    assert(E->getArg(0)->getType()->isWebAssemblyTableType());
+    Value *Table = EmitLValue(E->getArg(0)).emitRawPointer(*this);
     Value *Index = EmitScalarExpr(E->getArg(1));
     Value *Val = EmitScalarExpr(E->getArg(2));
     Value *NElems = EmitScalarExpr(E->getArg(3));
@@ -659,9 +659,9 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned 
BuiltinID,
     return Builder.CreateCall(Callee, {Table, Index, Val, NElems});
   }
   case WebAssembly::BI__builtin_wasm_table_copy: {
-    assert(E->getArg(0)->getType()->isArrayType());
-    Value *TableX = 
EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
-    Value *TableY = 
EmitArrayToPointerDecay(E->getArg(1)).emitRawPointer(*this);
+    assert(E->getArg(0)->getType()->isWebAssemblyTableType());
+    Value *TableX = EmitLValue(E->getArg(0)).emitRawPointer(*this);
+    Value *TableY = EmitLValue(E->getArg(1)).emitRawPointer(*this);
     Value *DstIdx = EmitScalarExpr(E->getArg(2));
     Value *SrcIdx = EmitScalarExpr(E->getArg(3));
     Value *NElems = EmitScalarExpr(E->getArg(4));
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d45c3eb35094f..8d9642ca8ac20 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8226,16 +8226,15 @@ NamedDecl *Sema::ActOnVariableDeclarator(
     }
   }
 
-  // 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);
-    }
+  // A WebAssemblyTableType is always in address space 1 (wasm_var). Don't 
apply
+  // the address space if the declaration has local storage (semantic checks
+  // elsewhere will produce an error anyway).
+  QualType VarTy = NewVD->getType();
+  bool IsWasmTable = VarTy->isWebAssemblyTableType();
+  if (IsWasmTable && !NewVD->hasLocalStorage()) {
+    QualType Type = Context.getAddrSpaceQualType(
+        VarTy, Context.getLangASForBuiltinAddressSpace(1));
+    NewVD->setType(Type);
   }
 
   LoadExternalExtnameUndeclaredIdentifiers();
@@ -8376,7 +8375,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
     // 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())
+    if (isWebAssemblyTableOrRefArrayType(Context, NewVD->getType()) &&
+        NewVD->isInvalidDecl())
       return nullptr;
 
     if (NewTemplate) {
@@ -9060,8 +9060,15 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
   }
 
   // WebAssembly tables must be static with a zero length and can't be
-  // declared within functions.
-  if (T->isWebAssemblyTableType()) {
+  // declared within functions. A valid table is represented by a
+  // WebAssemblyTableType; an array of a WebAssembly reference type that is not
+  // a valid table (e.g. has a non-zero or unspecified length) is detected here
+  // so that it can be diagnosed.
+  bool IsWasmTable = T->isWebAssemblyTableType();
+  bool IsWasmRefArray = false;
+  if (const auto *ATy = Context.getAsArrayType(T))
+    IsWasmRefArray = ATy->getElementType().isWebAssemblyReferenceType();
+  if (IsWasmTable || IsWasmRefArray) {
     if (getCurScope()->getParent()) { // Parent is null at top-level
       Diag(NewVD->getLocation(), diag::err_wasm_table_in_function);
       NewVD->setInvalidDecl();
@@ -9072,8 +9079,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
       NewVD->setInvalidDecl();
       return;
     }
-    const auto *ATy = dyn_cast<ConstantArrayType>(T.getTypePtr());
-    if (!ATy || ATy->getZExtSize() != 0) {
+    if (!IsWasmTable) {
       Diag(NewVD->getLocation(),
            diag::err_typecheck_wasm_table_must_have_zero_length);
       NewVD->setInvalidDecl();
@@ -11230,13 +11236,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator 
&D, DeclContext *DC,
         }
       }
     }
-    // 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();
-      }
+    // WebAssembly tables can't be used as function parameters. A parameter
+    // declared as an array of a reference type decays to a pointer, so check
+    // the pre-decay type as well.
+    if (Context.getTargetInfo().getTriple().isWasm() &&
+        isWebAssemblyTableOrRefArrayType(Context, Param->getOriginalType())) {
+      Diag(Param->getTypeSpecStartLoc(),
+           diag::err_wasm_table_as_function_parameter);
+      D.setInvalidType();
     }
   }
 
@@ -19401,6 +19408,10 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, 
QualType T,
   }
 
   QualType EltTy = Context.getBaseElementType(T);
+  // A WebAssembly table cannot be a struct or union member. Diagnose it via 
its
+  // (sizeless) reference element type.
+  if (const auto *WTT = EltTy->getAs<WebAssemblyTableType>())
+    EltTy = WTT->getElementType();
   if (!EltTy->isDependentType() && !EltTy->containsErrors()) {
     bool isIncomplete =
         LangOpts.HLSL // HLSL allows sizeless builtin types
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index b447eae2cee36..dcfa061ef467f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8885,6 +8885,14 @@ QualType Sema::CheckConditionalOperands(ExprResult 
&Cond, ExprResult &LHS,
   if (!RHSResult.isUsable()) return QualType();
   RHS = RHSResult;
 
+  // A WebAssembly table cannot be used as the condition of a conditional
+  // expression.
+  if (Cond.get()->getType()->isWebAssemblyTableType()) {
+    Diag(QuestionLoc, diag::err_wasm_table_conditional_expression)
+        << Cond.get()->getSourceRange();
+    return QualType();
+  }
+
   // C++ is sufficiently different to merit its own checker.
   if (getLangOpts().CPlusPlus)
     return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc);
@@ -13929,10 +13937,7 @@ inline QualType Sema::CheckLogicalOperands(ExprResult 
&LHS, ExprResult &RHS,
   // 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())) {
+  if (LHSTy->isWebAssemblyTableType() || RHSTy->isWebAssemblyTableType()) {
     return InvalidOperands(Loc, LHS, RHS);
   }
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 4e1652462b3ae..f58c95567779c 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -980,15 +980,15 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
     isPointer = true;
   }
 
-  // Cannot throw WebAssembly reference type.
-  if (Ty.isWebAssemblyReferenceType()) {
-    Diag(ThrowLoc, diag::err_wasm_reftype_tc) << 0 << E->getSourceRange();
+  // Cannot throw a WebAssembly table.
+  if (ExceptionObjectTy->isWebAssemblyTableType()) {
+    Diag(ThrowLoc, diag::err_wasm_table_art) << 2 << E->getSourceRange();
     return true;
   }
 
-  // Cannot throw WebAssembly table.
-  if (isPointer && Ty.isWebAssemblyReferenceType()) {
-    Diag(ThrowLoc, diag::err_wasm_table_art) << 2 << E->getSourceRange();
+  // Cannot throw WebAssembly reference type.
+  if (Ty.isWebAssemblyReferenceType()) {
+    Diag(ThrowLoc, diag::err_wasm_reftype_tc) << 0 << E->getSourceRange();
     return true;
   }
 
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 8f685feac4beb..44df438539846 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -1486,6 +1486,15 @@ void InitListChecker::CheckListElementTypes(const 
InitializedEntity &Entity,
     // Checks for scalar type are sufficient for these types too.
     CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
                     StructuredIndex);
+  } else if (DeclType->isWebAssemblyTableType()) {
+    // A WebAssembly table is a zero-length aggregate; only an empty 
initializer
+    // list (e.g. `= {}`) is valid.
+    if (IList->getNumInits() != 0) {
+      if (!VerifyOnly)
+        SemaRef.Diag(IList->getBeginLoc(), diag::err_illegal_initializer_type)
+            << DeclType;
+      hadError = true;
+    }
   } else if (DeclType->isDependentType()) {
     // C++ [over.match.class.deduct]p1.5:
     //   brace elision is not considered for any aggregate element that has a
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 27fee88d20c60..98e2f184b4825 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -35,6 +35,7 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaCUDA.h"
 #include "clang/Sema/SemaHLSL.h"
+#include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/SemaObjC.h"
 #include "clang/Sema/SemaOpenMP.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -4034,12 +4035,10 @@ StmtResult Sema::BuildReturnStmt(SourceLocation 
ReturnLoc, Expr *RetValExp,
   } 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_art) << 1;
-      return StmtError();
-    }
+  if (RetValExp &&
+      isWebAssemblyTableOrRefArrayType(Context, RetValExp->getType())) {
+    Diag(ReturnLoc, diag::err_wasm_table_art) << 1;
+    return StmtError();
   }
 
   // C++1z: discarded return statements are not considered when deducing a
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index d2bb312feadc1..d9c8f035f95be 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2135,13 +2135,20 @@ QualType Sema::BuildArrayType(QualType T, 
ArraySizeModifier ASM,
       return QualType();
   }
 
-  // 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()) {
+  // Multi-dimensional arrays of WebAssembly references are not allowed. The
+  // element type is either an array whose element is a reference type, or a
+  // WebAssembly table (a zero-length reference array already lowered to a
+  // WebAssemblyTableType).
+  if (Context.getTargetInfo().getTriple().isWasm()) {
+    if (T->isWebAssemblyTableType()) {
       Diag(Loc, diag::err_wasm_reftype_multidimensional_array);
       return QualType();
     }
+    if (const auto *ATy = dyn_cast<ArrayType>(T))
+      if (ATy->getElementType().isWebAssemblyReferenceType()) {
+        Diag(Loc, diag::err_wasm_reftype_multidimensional_array);
+        return QualType();
+      }
   }
 
   if (T->isSizelessType() && !T.isWebAssemblyReferenceType()) {
@@ -2363,6 +2370,18 @@ QualType Sema::BuildArrayType(QualType T, 
ArraySizeModifier ASM,
     }
   }
 
+  // On WebAssembly, a zero-length array of a reference type is a table. Give 
it
+  // a dedicated WebAssemblyTableType so that it is distinguished from an
+  // ordinary array. WebAssembly tables are not first-class: a table object may
+  // only be created by a global declaration and used as an argument to the
+  // table builtins. Other uses (locals, parameters, return values, struct or
+  // union members, taking a pointer, sizeof, ...) are rejected by the
+  // WebAssemblyTableType checks elsewhere.
+  if (const auto *CAT = dyn_cast<ConstantArrayType>(T))
+    if (CAT->getZExtSize() == 0 &&
+        CAT->getElementType().isWebAssemblyReferenceType())
+      T = Context.getWebAssemblyTableType(CAT->getElementType());
+
   return T;
 }
 
@@ -6301,6 +6320,11 @@ namespace {
       TL.setRBracketLoc(Chunk.EndLoc);
       TL.setSizeExpr(static_cast<Expr*>(Chunk.Arr.NumElts));
     }
+    void VisitWebAssemblyTableTypeLoc(WebAssemblyTableTypeLoc TL) {
+      // A WebAssembly table is formed from a zero-length array declarator.
+      assert(Chunk.Kind == DeclaratorChunk::Array);
+      TL.setKWLoc(Chunk.Loc);
+    }
     void VisitFunctionTypeLoc(FunctionTypeLoc TL) {
       assert(Chunk.Kind == DeclaratorChunk::Function);
       TL.setLocalRangeBegin(Chunk.Loc);
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 083460eb6e201..f72e19c13aabb 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -30,13 +30,13 @@ SemaWasm::SemaWasm(Sema &S) : SemaBase(S) {}
 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()) {
+  const auto *TTy = ArgExpr->getType()->getAs<WebAssemblyTableType>();
+  if (!TTy) {
     return S.Diag(ArgExpr->getBeginLoc(),
                   diag::err_wasm_builtin_arg_must_be_table_type)
            << ArgIndex + 1 << ArgExpr->getSourceRange();
   }
-  ElTy = ATy->getElementType();
+  ElTy = TTy->getElementType();
   return false;
 }
 
diff --git a/clang/test/Sema/wasm-refs-and-tables.c 
b/clang/test/Sema/wasm-refs-and-tables.c
index dd8536c52cd03..6cfc8a8664535 100644
--- a/clang/test/Sema/wasm-refs-and-tables.c
+++ b/clang/test/Sema/wasm-refs-and-tables.c
@@ -74,7 +74,7 @@ __externref_t func(__externref_t ref) {
   _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(__externref_t[0]);    // expected-error {{invalid application of 
'alignof' to WebAssembly table}}
   _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 not allowed}}
   _Alignof(__externref_t *);     // expected-error {{pointer to WebAssembly 
reference type is not allowed}}
@@ -92,8 +92,8 @@ __externref_t func(__externref_t ref) {
   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 == other_table;           // expected-error {{invalid operands to 
binary expression ('__attribute__((address_space(1))) __externref_t[0]' and 
'__attribute__((address_space(1))) __externref_t[0]')}}
-  table !=- table;                // expected-error {{invalid argument type 
'__attribute__((address_space(1))) __externref_t *' to unary expression}}
-  !table;                         // expected-error {{invalid argument type 
'__attribute__((address_space(1))) __externref_t *' to unary expression}}
+  table !=- table;                // expected-error {{invalid argument type 
'__externref_t[0]' to unary expression}}
+  !table;                         // expected-error {{invalid argument type 
'__externref_t[0]' 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}}
diff --git a/clang/test/SemaCXX/wasm-refs-and-tables.cpp 
b/clang/test/SemaCXX/wasm-refs-and-tables.cpp
index 3d6ead07fd530..c8f16b09aa4e8 100644
--- a/clang/test/SemaCXX/wasm-refs-and-tables.cpp
+++ b/clang/test/SemaCXX/wasm-refs-and-tables.cpp
@@ -19,7 +19,7 @@ __externref_t func(__externref_t ref)  throw(__externref_t) { 
// expected-error
 #endif
 
 void *ret_void_ptr() {
-  throw table;              // expected-error {{cannot throw a WebAssembly 
reference type}}
+  throw table;              // expected-error {{cannot throw a WebAssembly 
table}}
   throw r1;                 // expected-error {{cannot throw a WebAssembly 
reference type}}
   try {}
   catch (__externref_t T) { // expected-error {{cannot catch a WebAssembly 
reference type}}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to