Skip to content

Instantly share code, notes, and snippets.

@asb
Created May 16, 2022 15:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asb/b8701efe35cf99bc8fd606b9ca984337 to your computer and use it in GitHub Desktop.
Save asb/b8701efe35cf99bc8fd606b9ca984337 to your computer and use it in GitHub Desktop.
From: Alex Bradbury <asb@igalia.com>
Subject: [clang][WebAssembly] Implement semantic restrictions for reference
types
In addition to the restrictions for sizeless types, it isn't possible to
take the address of a WebAssembly reference type, or to declare a
pointer to one. It is also not possible to pass reference types to a
vararg function.
Additionally, global sizeless types aren't allowed in general, but we do
allow global Wasm references. This patch also enables them.
---
clang/include/clang/AST/Type.h | 3 +
.../clang/Basic/DiagnosticSemaKinds.td | 10 ++
clang/lib/AST/Type.cpp | 7 ++
clang/lib/Sema/SemaDecl.cpp | 3 +-
clang/lib/Sema/SemaExpr.cpp | 18 +++
clang/lib/Sema/SemaType.cpp | 16 +++
clang/test/Sema/wasm-refs-and-tables.c | 71 ++++++++++++
clang/test/SemaCXX/wasm-refs-and-tables.cpp | 103 ++++++++++++++++++
8 files changed, 230 insertions(+), 1 deletion(-)
create mode 100644 clang/test/Sema/wasm-refs-and-tables.c
create mode 100644 clang/test/SemaCXX/wasm-refs-and-tables.cpp
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index a087567f9cd2..1338d936edc8 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1909,6 +1909,9 @@ public:
bool isSizelessType() const;
bool isSizelessBuiltinType() const;
+ /// Check if this is a WebAssembly Reference Type.
+ bool isWebAssemblyReferenceType() 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/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d8f87747e58d..d3d88a4d453d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11628,4 +11628,14 @@ def err_non_designated_init_used : Error<
"a randomized struct can only be initialized with a designated initializer">;
def err_cast_from_randomized_struct : Error<
"casting from randomized structure pointer type %0 to %1">;
+
+// WebAssembly reference type and table diagnostics
+def err_wasm_reference_pointer : Error<
+ "pointers to WebAssembly reference types are illegal">;
+def err_wasm_reference_reference : Error<
+ "references to WebAssembly reference types are illegal">;
+def err_wasm_capture_reference : Error<
+ "cannot capture WebAssembly reference">;
+def err_wasm_addrof_reference : Error<
+ "cannot take address of WebAssembly reference">;
} // end of sema component.
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 954810af401f..145fa3202dcf 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2324,6 +2324,13 @@ bool Type::isSizelessBuiltinType() const {
bool Type::isSizelessType() const { return isSizelessBuiltinType(); }
+bool Type::isWebAssemblyReferenceType() const {
+ const BuiltinType *BT = getAs<BuiltinType>();
+ if (BT && BT->getKind() == BuiltinType::WasmExternRef)
+ return true;
+ return false;
+}
+
bool Type::isVLSTBuiltinType() const {
if (const BuiltinType *BT = getAs<BuiltinType>()) {
switch (BT->getKind()) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 498dacf8d844..e86ee4e113bc 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8425,7 +8425,8 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
return;
}
- if (!NewVD->hasLocalStorage() && T->isSizelessType()) {
+ if (!NewVD->hasLocalStorage() && T->isSizelessType() &&
+ !T->isWebAssemblyReferenceType()) {
Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T;
NewVD->setInvalidDecl();
return;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 12b00c05995f..f24ec7962157 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -936,6 +936,11 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct)
return VAK_Invalid;
+ if (Context.getTargetInfo().getTriple().isWasm() &&
+ Ty->isWebAssemblyReferenceType()) {
+ return VAK_Invalid;
+ }
+
if (Ty.isCXX98PODType(Context))
return VAK_Valid;
@@ -14373,6 +14378,13 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
if (op->getType()->isObjCObjectType())
return Context.getObjCObjectPointerType(op->getType());
+ if (Context.getTargetInfo().getTriple().isWasm() &&
+ op->getType()->isWebAssemblyReferenceType()) {
+ Diag(OpLoc, diag::err_wasm_addrof_reference)
+ << OrigOp.get()->getSourceRange();
+ return QualType();
+ }
+
CheckAddressOfPackedMember(op);
return Context.getPointerType(op->getType());
@@ -18389,6 +18401,12 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
}
+ if (BuildAndDiagnose && S.Context.getTargetInfo().getTriple().isWasm() &&
+ CaptureType.getNonReferenceType()->isWebAssemblyReferenceType()) {
+ S.Diag(Loc, diag::err_wasm_capture_reference);
+ Invalid = true;
+ }
+
// Compute the type of the field that will capture this variable.
if (ByRef) {
// C++11 [expr.prim.lambda]p15:
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 0bb352e914a8..38565f1dffd4 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2147,6 +2147,14 @@ QualType Sema::BuildPointerType(QualType T,
if (getLangOpts().OpenCL)
T = deduceOpenCLPointeeAddrSpace(*this, T);
+ // In WebAssembly, pointers to reference types are illegal.
+ if (getASTContext().getTargetInfo().getTriple().isWasm()) {
+ if (T->isWebAssemblyReferenceType()) {
+ Diag(Loc, diag::err_wasm_reference_pointer);
+ return QualType();
+ }
+ }
+
// Build the pointer type.
return Context.getPointerType(T);
}
@@ -2222,6 +2230,14 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
if (getLangOpts().OpenCL)
T = deduceOpenCLPointeeAddrSpace(*this, T);
+ // In WebAssembly, references to reference types are illegal.
+ if (getASTContext().getTargetInfo().getTriple().isWasm()) {
+ if (T->isWebAssemblyReferenceType()) {
+ Diag(Loc, diag::err_wasm_reference_reference);
+ return QualType();
+ }
+ }
+
// Handle restrict on references.
if (LValueRef)
return Context.getLValueReferenceType(T, SpelledAsLValue);
diff --git a/clang/test/Sema/wasm-refs-and-tables.c b/clang/test/Sema/wasm-refs-and-tables.c
new file mode 100644
index 000000000000..345050737231
--- /dev/null
+++ b/clang/test/Sema/wasm-refs-and-tables.c
@@ -0,0 +1,71 @@
+// 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 {{pointers to WebAssembly reference types are illegal}}
+__externref_t **t2; // expected-error {{pointers to WebAssembly reference types are illegal}}
+__externref_t ******t3; // expected-error {{pointers to WebAssembly reference types are illegal}}
+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 {{pointers to WebAssembly reference types are illegal}}
+ __externref_t ****f6; // expected-error {{pointers to WebAssembly reference types are illegal}}
+};
+
+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 {{pointers to WebAssembly reference types are illegal}}
+ __externref_t ****f6; // expected-error {{pointers to WebAssembly reference types are illegal}}
+};
+
+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 {{pointers to WebAssembly reference types are illegal}}
+void illegal_argument_4(__externref_t ***table); // expected-error {{pointers to WebAssembly reference types are illegal}}
+
+__externref_t *illegal_return_1(); // expected-error {{pointers to WebAssembly reference types are illegal}}
+__externref_t ***illegal_return_2(); // expected-error {{pointers to WebAssembly reference types are illegal}}
+
+void varargs(int, ...);
+
+__externref_t func(__externref_t ref) {
+ &ref; // expected-error {{cannot take address of WebAssembly reference}}
+ int foo = 40;
+ (__externref_t *)(&foo); // expected-error {{pointers to WebAssembly reference types are illegal}}
+ (__externref_t ****)(&foo); // expected-error {{pointers to WebAssembly reference types are illegal}}
+ 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 {{pointers to WebAssembly reference types are illegal}}
+ sizeof(__externref_t ***); // expected-error {{pointers to WebAssembly reference types are illegal}};
+ // 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 {{pointers to WebAssembly reference types are illegal}}
+ _Alignof(__externref_t ***); // expected-error {{pointers to WebAssembly reference types are illegal}};
+ varargs(1, ref); // expected-error {{cannot pass expression of type '__externref_t' to variadic function}}
+
+ 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
index 000000000000..25452053e8a2
--- /dev/null
+++ b/clang/test/SemaCXX/wasm-refs-and-tables.cpp
@@ -0,0 +1,103 @@
+// 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 {{references to WebAssembly reference types are illegal}}
+__externref_t &ref_ref2(ref); // expected-error {{references to WebAssembly reference types are illegal}}
+
+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 {{references to WebAssembly reference types are illegal}}
+void illegal_argument_2(__externref_t (&t)[0]); // expected-error {{array has sizeless element type '__externref_t'}}
+
+__externref_t &illegal_return_1(); // expected-error {{references to WebAssembly reference types are illegal}}
+__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 {{pointers to WebAssembly reference types are illegal}}
+void illegal_throw3() throw(__externref_t &); // expected-error {{references to WebAssembly reference types are illegal}}
+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 {{pointers to WebAssembly reference types are illegal}}
+ __externref_t ****f6; // expected-error {{pointers to WebAssembly reference types are illegal}}
+ __externref_t (*f7)[0]; // expected-error {{array has sizeless element type '__externref_t'}}
+};
+
+struct AStruct {};
+
+template <typename T>
+struct TemplatedStruct {
+ T f; // expected-error {{field has sizeless type '__externref_t'}}
+ void foo(T);
+ T bar(void);
+ T arr[0]; // expected-error {{array has sizeless element type '__externref_t'}}
+ T *ptr; // expected-error {{pointers to WebAssembly reference types are illegal}}
+};
+
+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 {{pointers to WebAssembly reference types are illegal}}
+ static_cast<int>(ref); // expected-error {{static_cast from '__externref_t' to 'int' is not allowed}}
+ __externref_t(10); // expected-error {{functional-style cast from 'int' to '__externref_t' is not allowed}}
+ int i(ref); // expected-error {{cannot initialize a variable of type 'int' with an lvalue of type '__externref_t'}}
+ const_cast<__externref_t[0]>(table); // expected-error {{array has sizeless element type '__externref_t'}}
+ const_cast<__externref_t *>(table); // expected-error {{pointers to WebAssembly reference types are illegal}}
+ reinterpret_cast<__externref_t>(foo); // expected-error {{reinterpret_cast from 'int' to '__externref_t' is not allowed}}
+ reinterpret_cast<int>(ref); // expected-error {{reinterpret_cast from '__externref_t' to 'int' is not allowed}}
+ int iarr[0];
+ reinterpret_cast<__externref_t[0]>(iarr); // expected-error {{array has sizeless element type '__externref_t'}}
+ reinterpret_cast<__externref_t *>(iarr); // expected-error {{pointers to WebAssembly reference types are illegal}}
+ 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 {{pointers to WebAssembly reference types are illegal}}
+
+ TemplatedStruct<__externref_t> ts1; // expected-note {{in instantiation}}
+ TemplatedStruct<__externref_t *> ts2; // expected-error {{pointers to WebAssembly reference types are illegal}}
+ TemplatedStruct<__externref_t &> ts3; // expected-error {{references to WebAssembly reference types are illegal}}
+ 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 {{pointers to WebAssembly reference types are illegal}}
+ auto fn3 = [](__externref_t &x) { return x; }; // expected-error {{references to WebAssembly reference types are illegal}}
+ 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 {{pointers to WebAssembly reference types are illegal}}
+ }
+ try {
+ } catch (__externref_t &) { // expected-error {{references to WebAssembly reference types are illegal}}
+ }
+ 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'}}
+}
--
2.36.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment