diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -2302,6 +2302,138 @@
atomic_add(a, 1);
}
+WebAssembly Features
+====================
+
+Clang supports the WebAssembly features documented below. For further
+information related to the semantics of the builtins, please refer to the `WebAssembly Specification `_.
+In this section, when we refer to reference types, we are reffering to
+WebAssembly reference types, not C++ reference types unless stated
+otherwise.
+
+``__builtin_wasm_table_set``
+----------------------------
+
+This builtin function stores a value in a WebAssembly table.
+It takes three arguments.
+The first argument is the table to store a value into, the second
+argument is the index to which to store the value into, and the
+third argument is a value of reference type to store in the table.
+It returns nothing.
+
+.. code-block:: c++
+
+ static __externref_t table[0];
+ extern __externref_t JSObj;
+
+ void store(int index) {
+ __builtin_wasm_table_set(table, index, JSObj);
+ }
+
+``__builtin_wasm_table_get``
+----------------------------
+
+This builtin function is the counterpart to ``__builtin_wasm_table_set``
+and loads a value from a WebAssembly table of reference typed values.
+It takes 2 arguments.
+The first argument is a table of reference typed values and the
+second argument is an index from which to load the value. It returns
+the loaded reference typed value.
+
+.. code-block:: c++
+
+ static __externref_t table[0];
+
+ __externref_t load(int index) {
+ __externref_t Obj = __builtin_wasm_table_get(table, index);
+ return Obj;
+ }
+
+``__builtin_wasm_table_size``
+-----------------------------
+
+This builtin function returns the size of the WebAssembly table.
+Takes the table as an argument and returns an unsigned integer (``size_t``)
+with the current table size.
+
+.. code-block:: c++
+
+ typedef void (*__funcref funcref_t)();
+ static __funcref table[0];
+
+ size_t getSize() {
+ return __builtin_wasm_table_size(table);
+ }
+
+``__builtin_wasm_table_grow``
+-----------------------------
+
+This builtin function grows the WebAssembly table by a certain amount.
+Currently, as all WebAssembly tables created in C/C++ are zero-sized,
+this always needs to be called to grow the table.
+
+It takes three arguments. The first argument is the WebAssembly table
+to grow. The second argument is the reference typed value to store in
+the new table entries (the initialization value), and the third argument
+is the amound to grow the table by. It returns the previous table size
+or -1. It will return -1 if not enough space could be allocated.
+
+.. code-block:: c++
+
+ typedef void (*__funcref funcref_t)();
+ static __funcref table[0];
+
+ // grow returns the new table size or -1 on error.
+ int grow(__funcref fn, int delta) {
+ int prevSize = __builtin_wasm_table_grow(table, fn, delta);
+ if (prevSize == -1)
+ return -1;
+ return prevSize + delta;
+ }
+
+``__builtin_wasm_table_fill``
+-----------------------------
+
+This builtin function sets all the entries of a WebAssembly table to a given
+reference typed value. It takes four arguments. The first argument is
+the WebAssembly table, the second argument is the index that starts the
+range, the third argument is the value to set in the new entries, and
+the fourth and the last argument is the size of the range. It returns
+nothing.
+
+.. code-block:: c++
+
+ static __externref_t table[0];
+
+ // resets a table by setting all of its entries to a given value.
+ void reset(__externref_t Obj) {
+ int Size = __builtin_wasm_table_size(table);
+ __builtin_wasm_table_fill(table, 0, Obj, Size);
+ }
+
+``__builtin_wasm_table_copy``
+-----------------------------
+
+This builtin function copies elements from a source WebAssembly table
+to a possibly overlapping destination region. It takes five arguments.
+The first argument is the destination WebAssembly table, and the second
+argument is the source WebAssembly table. The third argument is the
+destination index from where the copy starts, the fourth argument is the
+source index from there the copy starts, and the fifth and last argument
+is the number of elements to copy. It returns nothing.
+
+.. code-block:: c++
+
+ static __externref_t tableSrc[0];
+ static __externref_t tableDst[0];
+
+ // Copy nelem elements from [src, src + nelem - 1] in tableSrc to
+ // [dst, dst + nelem - 1] in tableDst
+ void copy(int dst, int src, int nelem) {
+ __builtin_wasm_table_copy(tableDst, tableSrc, dst, src, nelem);
+ }
+
+
Builtin Functions
=================
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -908,6 +908,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.
@@ -2034,10 +2043,14 @@
/// Returns true for RVV scalable vector types.
bool isRVVSizelessBuiltinType() 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.
diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def
--- a/clang/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/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, "zi", "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
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11838,4 +11838,34 @@
"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_art : Error<
+ "cannot %select{assign|return|throw|subscript}0 a WebAssembly table">;
+def err_wasm_reftype_tc : Error<
+ "cannot %select{throw|catch}0 a WebAssembly reference type">;
+def err_wasm_reftype_exception_spec : Error<
+ "WebAssembly reference type not allowed in exception specification">;
+def err_wasm_table_must_be_static : Error<
+ "WebAssembly table must be static">;
+def err_wasm_reftype_multidimensional_array : Error<
+ "multi-dimensional arrays of WebAssembly references are not allowed">;
+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.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13623,6 +13623,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 {
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2366,16 +2366,22 @@
return false;
}
-bool Type::isWebAssemblyReferenceType() const {
- return isWebAssemblyExternrefType();
-}
-
bool Type::isWebAssemblyExternrefType() const {
if (const auto *BT = getAs())
return BT->getKind() == BuiltinType::WasmExternRef;
return false;
}
+bool Type::isWebAssemblyTableType() const {
+ if (const auto *ATy = dyn_cast(this))
+ return ATy->getElementType().isWebAssemblyReferenceType();
+
+ if (const auto *PTy = dyn_cast(this))
+ return PTy->getPointeeType().isWebAssemblyReferenceType();
+
+ return false;
+}
+
bool Type::isSizelessType() const { return isSizelessBuiltinType(); }
bool Type::isSVESizelessBuiltinType() const {
@@ -2698,6 +2704,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 =
diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/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;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -19712,6 +19712,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;
}
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/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"
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -2746,6 +2746,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,
@@ -2921,6 +2930,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);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4830,6 +4830,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;
@@ -12319,6 +12331,10 @@
}
}
+ if (RetValExp && RetValExp->getType()->isWebAssemblyTableType()) {
+ Diag(ReturnLoc, diag::err_wasm_table_art) << 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())
@@ -16046,6 +16062,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;
@@ -18328,6 +18351,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(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
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -7850,6 +7850,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(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);
@@ -8006,6 +8018,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()
@@ -8612,6 +8631,28 @@
}
}
+ // WebAssembly tables must be static with a zero length and can't be
+ // declared within functions.
+ if (T->isWebAssemblyTableType()) {
+ if (getCurScope()->getParent()) { // Parent is null at top-level
+ 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(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() ||
NewVD->hasAttr())
@@ -8683,7 +8724,7 @@
}
if (!NewVD->hasLocalStorage() && T->isSizelessType() &&
- !T->isWebAssemblyReferenceType()) {
+ !T.isWebAssemblyReferenceType()) {
Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T;
NewVD->setInvalidDecl();
return;
@@ -10691,6 +10732,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.
@@ -13078,6 +13127,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_art) << 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
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -16488,6 +16488,11 @@
if (!Invalid && (Mode == 0 || !BaseType->isVoidType()) &&
!BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK))
Invalid = true;
+
+ if (!Invalid && BaseType.isWebAssemblyReferenceType()) {
+ Diag(Loc, diag::err_wasm_reftype_tc) << 1;
+ Invalid = true;
+ }
if (!Invalid && Mode != 1 && BaseType->isSizelessType()) {
Diag(Loc, diag::err_catch_sizeless) << (Mode == 2 ? 1 : 0) << BaseType;
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -172,6 +172,12 @@
RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
return ReturnValueOnError;
+ // WebAssembly reference types can't be used in exception specifications.
+ if (PointeeT.isWebAssemblyReferenceType()) {
+ Diag(Range.getBegin(), diag::err_wasm_reftype_exception_spec);
+ return true;
+ }
+
// The MSVC compatibility mode doesn't extend to sizeless types,
// so diagnose them separately.
if (PointeeT->isSizelessType() && Kind != 1) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -940,7 +940,7 @@
return VAK_Invalid;
if (Context.getTargetInfo().getTriple().isWasm() &&
- Ty->isWebAssemblyReferenceType()) {
+ Ty.isWebAssemblyReferenceType()) {
return VAK_Invalid;
}
@@ -4297,6 +4297,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
@@ -4589,6 +4598,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;
@@ -4898,7 +4916,12 @@
matSubscriptE->getRowIdx(),
ArgExprs.front(), rbLoc);
}
-
+ if (base->getType()->isWebAssemblyTableType()) {
+ Diag(base->getExprLoc(), diag::err_wasm_table_art)
+ << SourceRange(base->getBeginLoc(), rbLoc) << 3;
+ return ExprError();
+ }
+
// Handle any non-overload placeholder types in the base and index
// expressions. We can't handle overloads here because the other
// operand might be an overloadable type, in which case the overload
@@ -5856,6 +5879,7 @@
if (!ResultType.hasQualifiers())
VK = VK_PRValue;
} else if (!ResultType->isDependentType() &&
+ !ResultType.isWebAssemblyReferenceType() &&
RequireCompleteSizedType(
LLoc, ResultType,
diag::err_subscript_incomplete_or_sizeless_type, BaseExpr))
@@ -7384,6 +7408,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))
@@ -8976,8 +9010,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.
@@ -12451,6 +12491,11 @@
S.inTemplateInstantiation())
return;
+ // WebAssembly Tables cannot be compared, therefore shouldn't emit
+ // Tautological diagnostics.
+ if (LHSType->isWebAssemblyTableType() || RHSType->isWebAssemblyTableType())
+ return;
+
// Comparisons between two array types are ill-formed for operator<=>, so
// we shouldn't emit any additional warnings about it.
if (Opc == BO_Cmp && LHSType->isArrayType() && RHSType->isArrayType())
@@ -12837,6 +12882,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 =
@@ -13755,6 +13806,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(LHSTy);
+ const auto *RHSATy = dyn_cast(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.
@@ -14296,6 +14357,12 @@
return QualType();
}
+ // WebAssembly tables can't be used on RHS of an assignment expression.
+ if (RHSType->isWebAssemblyTableType()) {
+ Diag(Loc, diag::err_wasm_table_art) << 0;
+ return QualType();
+ }
+
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
Expr *RHSCheck = RHS.get();
@@ -14903,11 +14970,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);
@@ -16092,6 +16167,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)) {
@@ -19045,7 +19127,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;
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -976,6 +976,19 @@
Ty = Ptr->getPointeeType();
isPointer = true;
}
+
+ // Cannot throw WebAssembly reference type.
+ if (Ty.isWebAssemblyReferenceType()) {
+ Diag(ThrowLoc, diag::err_wasm_reftype_tc) << 0 << E->getSourceRange();
+ return true;
+ }
+
+ // Cannot throw WebAssembly table.
+ if (isPointer && Ty.isWebAssemblyReferenceType()) {
+ Diag(ThrowLoc, diag::err_wasm_table_art) << 2 << E->getSourceRange();
+ return true;
+ }
+
if (!isPointer || !Ty->isVoidType()) {
if (RequireCompleteType(ThrowLoc, Ty,
isPointer ? diag::err_throw_incomplete_ptr
@@ -6562,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
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12020,7 +12020,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()});
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/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(RetValExp->getType());
+ if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) {
+ Diag(ReturnLoc, diag::err_wasm_table_art) << 1;
+ return StmtError();
+ }
+ }
+
// C++1z: discarded return statements are not considered when deducing a
// return type.
if (ExprEvalContexts.back().isDiscardedStatementContext() &&
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2199,11 +2199,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.
@@ -2281,12 +2289,16 @@
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.
if (LValueRef)
@@ -2491,12 +2503,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(T);
+ if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) {
+ Diag(Loc, diag::err_wasm_reftype_multidimensional_array);
+ return QualType();
+ }
+ }
+
+ if (T->isSizelessType() && !T.isWebAssemblyReferenceType()) {
Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T;
return QualType();
}
@@ -2615,7 +2637,7 @@
<< ArraySize->getSourceRange();
return QualType();
}
- if (ConstVal == 0) {
+ if (ConstVal == 0 && !T.isWebAssemblyReferenceType()) {
// GCC accepts zero sized static arrays. We allow them when
// we're not in a SFINAE context.
Diag(ArraySize->getBeginLoc(),
@@ -3004,6 +3026,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:
diff --git a/clang/test/CodeGen/WebAssembly/builtins-table.c b/clang/test/CodeGen/WebAssembly/builtins-table.c
new file mode 100644
--- /dev/null
+++ b/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);
+}
diff --git a/clang/test/Sema/builtins-wasm.c b/clang/test/Sema/builtins-wasm.c
new file mode 100644
--- /dev/null
+++ b/clang/test/Sema/builtins-wasm.c
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -target-feature +reference-types %s
+
+#define EXPR_HAS_TYPE(expr, type) _Generic((expr), type : 1, default : 0)
+
+static __externref_t table[0];
+
+typedef void (*__funcref funcref_t)();
+void test_ref_null() {
+ funcref_t func = __builtin_wasm_ref_null_func(0); // expected-error {{too many arguments to function call, expected 0, have 1}}
+}
+
+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}}
+
+ _Static_assert(EXPR_HAS_TYPE(__builtin_wasm_table_size(table), unsigned long), "");
+}
+
+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}}
+
+ _Static_assert(EXPR_HAS_TYPE(__builtin_wasm_table_grow(table, ref, size), int), "");
+}
+
+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}}
+ __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);
+}
diff --git a/clang/test/Sema/wasm-refs-and-table-ped.c b/clang/test/Sema/wasm-refs-and-table-ped.c
new file mode 100644
--- /dev/null
+++ b/clang/test/Sema/wasm-refs-and-table-ped.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify=expected -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
+// No error should be emitted.
+static __externref_t table[0]; // expected-no-diagnostics
diff --git a/clang/test/Sema/wasm-refs-and-tables.c b/clang/test/Sema/wasm-refs-and-tables.c
new file mode 100644
--- /dev/null
+++ b/clang/test/Sema/wasm-refs-and-tables.c
@@ -0,0 +1,133 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,conly -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
+// RUN: %clang_cc1 -x c++ -std=c++17 -fsyntax-only -verify=expected,cpp -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 not allowed}}
+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] = {};
+static __externref_t another_table[] = {}; // expected-error {{only zero-length WebAssembly tables are currently supported}}
+
+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 not allowed}}
+ __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 not allowed}}
+ __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 not allowed}}
+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}}
+void illegal_argument_6(__externref_t table[0]); // expected-error {{cannot use WebAssembly table as a function parameter}}
+
+__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, ...);
+typedef void (*__funcref funcref_t)();
+typedef void (*__funcref __funcref funcref_fail_t)(); // expected-warning {{attribute '__funcref' is already applied}}
+
+__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 not allowed}}
+ 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 not allowed}}
+ _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 not allowed}}
+ static __externref_t(*lt4)[0]; // expected-error {{cannot form a pointer to a WebAssembly table}}
+ // conly-error@+2 {{cannot use WebAssembly table as a function parameter}}
+ // cpp-error@+1 {{no matching function for call to 'illegal_argument_1'}}
+ illegal_argument_1(table);
+ 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 == 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}}
+ 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}}
+ table ? : other_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}}
+ (void)table;
+
+ table[0]; // expected-error {{cannot subscript a WebAssembly table}}
+ table[0] = ref; // expected-error {{cannot subscript a WebAssembly table}}
+
+ int i = 0;
+ __externref_t oh_no_vlas[i]; // expected-error {{WebAssembly table cannot be declared within a function}}
+
+ return ref;
+}
+
+void foo() {
+ static __externref_t t[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
+ {
+ static __externref_t t2[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
+ for (;;) {
+ static __externref_t t3[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
+ }
+ }
+ int i = ({
+ static __externref_t t4[0]; // expected-error {{WebAssembly table cannot be declared within a function}}
+ 1;
+ });
+}
+
+void *ret_void_ptr() {
+ return table; // expected-error {{cannot return a WebAssembly table}}
+}
diff --git a/clang/test/Sema/wasm-refs.c b/clang/test/Sema/wasm-refs.c
deleted file mode 100644
--- a/clang/test/Sema/wasm-refs.c
+++ /dev/null
@@ -1,75 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -triple wasm32 -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 {{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 table[0]; // expected-error {{array has sizeless element type '__externref_t'}}
-
-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 *f5; // expected-error {{pointer to WebAssembly reference type is not allowed}}
- __externref_t ****f6; // expected-error {{pointer to WebAssembly reference type is not allowed}}
-};
-
-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 *f5; // expected-error {{pointer to WebAssembly reference type is not allowed}}
- __externref_t ****f6; // expected-error {{pointer to WebAssembly reference type is not allowed}}
-};
-
-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_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}}
-
-__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}}
-
-void varargs(int, ...);
-typedef void (*__funcref funcref_t)();
-typedef void (*__funcref __funcref funcref_fail_t)(); // expected-warning {{attribute '__funcref' is already applied}}
-
-__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 {{array has sizeless element type '__externref_t'}}
- sizeof(__externref_t[0][0]); // expected-error {{array has sizeless element type '__externref_t'}}
- 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 {{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}}
-
- funcref_t func = __builtin_wasm_ref_null_func(0); // expected-error {{too many arguments to function call, expected 0, have 1}}
-
- return ref;
-}
diff --git a/clang/test/SemaCXX/wasm-refs-and-tables.cpp b/clang/test/SemaCXX/wasm-refs-and-tables.cpp
new file mode 100644
--- /dev/null
+++ b/clang/test/SemaCXX/wasm-refs-and-tables.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -fsyntax-only -verify -triple wasm32 -Wno-unused-value -target-feature +reference-types %s
+// RUN: %clang_cc1 -std=c++20 -fcxx-exceptions -fexceptions -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.
+
+// Using c++11 to test dynamic exception specifications (which are not
+// allowed in c++17).
+
+// Unlike standard sizeless types, reftype globals are supported.
+__externref_t r1;
+static __externref_t table[0];
+
+#if (_cplusplus == 201103L)
+__externref_t func(__externref_t ref) throw(__externref_t) { // expected-error {{WebAssembly reference type not allowed in exception specification}}
+ return ref;
+}
+#endif
+
+void *ret_void_ptr() {
+ throw table; // expected-error {{cannot throw a WebAssembly reference type}}
+ throw r1; // expected-error {{cannot throw a WebAssembly reference type}}
+ try {}
+ catch (__externref_t T) { // expected-error {{cannot catch a WebAssembly reference type}}
+ (void)0;
+ }
+
+ return table; // expected-error {{cannot return a WebAssembly table}}
+}
diff --git a/clang/test/SemaCXX/wasm-refs.cpp b/clang/test/SemaCXX/wasm-refs.cpp
deleted file mode 100644
--- a/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
-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(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(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'}}
-}
diff --git a/llvm/include/llvm/CodeGen/WasmAddressSpaces.h b/llvm/include/llvm/CodeGen/WasmAddressSpaces.h
new file mode 100644
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/WasmAddressSpaces.h
@@ -0,0 +1,48 @@
+//===--- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_WASM_ADDRESS_SPACES_H
+#define LLVM_CODEGEN_WASM_ADDRESS_SPACES_H
+
+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
+
+#endif // LLVM_CODEGEN_WASM_ADDRESS_SPACES_H
diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
--- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
+++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
@@ -18,6 +18,7 @@
#include "MCTargetDesc/WebAssemblyMCTypeUtilities.h"
#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/CodeGen/MachineValueType.h"
+#include "llvm/CodeGen/WasmAddressSpaces.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/MC/MCSymbolWasm.h"
@@ -27,41 +28,21 @@
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);
+/// Return true if this is a WebAssembly Externref Type.
+inline bool isWebAssemblyExternrefType(const Type *Ty) {
+ return Ty->getPointerAddressSpace() ==
+ WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF;
}
-inline bool isFuncrefType(const Type *Ty) {
- return isa(Ty) &&
- Ty->getPointerAddressSpace() ==
- WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF;
-}
-inline bool isExternrefType(const Type *Ty) {
- return isa(Ty) &&
- Ty->getPointerAddressSpace() ==
- WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF;
+
+/// Return true if this is a WebAssembly Funcref Type.
+inline bool isWebAssemblyFuncrefType(const Type *Ty) {
+ return Ty->getPointerAddressSpace() ==
+ WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF;
}
-inline bool isRefType(const Type *Ty) {
- return isFuncrefType(Ty) || isExternrefType(Ty);
+
+/// Return true if this is a WebAssembly Reference Type.
+inline bool isWebAssemblyReferenceType(const Type *Ty) {
+ return isWebAssemblyExternrefType(Ty) || isWebAssemblyFuncrefType(Ty);
}
// Convert StringRef to ValType / HealType / BlockType
diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
--- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
+++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.cpp
@@ -77,13 +77,13 @@
// that is a reference type.
wasm::ValType ValTy;
bool IsTable = false;
- if (GlobalVT->isArrayTy() &&
- WebAssembly::isRefType(GlobalVT->getArrayElementType())) {
+ if (GlobalVT->isArrayTy() && WebAssembly::isWebAssemblyReferenceType(
+ GlobalVT->getArrayElementType())) {
IsTable = true;
const Type *ElTy = GlobalVT->getArrayElementType();
- if (WebAssembly::isExternrefType(ElTy))
+ if (WebAssembly::isWebAssemblyExternrefType(ElTy))
ValTy = wasm::ValType::EXTERNREF;
- else if (WebAssembly::isFuncrefType(ElTy))
+ else if (WebAssembly::isWebAssemblyFuncrefType(ElTy))
ValTy = wasm::ValType::FUNCREF;
else
report_fatal_error("unhandled reference type");
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -1203,7 +1203,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())) {
+ WebAssembly::isWebAssemblyFuncrefType(CLI.CB->getCalledOperand()->getType())) {
// 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
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
+++ b/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(&*I);
IntToPtrInst *ITP = dyn_cast(&*I);
- if (!(PTI && WebAssembly::isRefType(PTI->getPointerOperand()->getType())) &&
- !(ITP && WebAssembly::isRefType(ITP->getDestTy())))
+ if (!(PTI && WebAssembly::isWebAssemblyReferenceType(
+ PTI->getPointerOperand()->getType())) &&
+ !(ITP && WebAssembly::isWebAssemblyReferenceType(ITP->getDestTy())))
continue;
UndefValue *U = UndefValue::get(I->getType());