Created
May 16, 2022 15:12
-
-
Save asb/b8701efe35cf99bc8fd606b9ca984337 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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