1*0fca6ea1SDimitry Andric //===------ SemaWasm.cpp ---- WebAssembly target-specific routines --------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This file implements semantic analysis functions specific to WebAssembly. 10*0fca6ea1SDimitry Andric // 11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric #include "clang/Sema/SemaWasm.h" 14*0fca6ea1SDimitry Andric #include "clang/AST/ASTContext.h" 15*0fca6ea1SDimitry Andric #include "clang/AST/Decl.h" 16*0fca6ea1SDimitry Andric #include "clang/AST/Type.h" 17*0fca6ea1SDimitry Andric #include "clang/Basic/AddressSpaces.h" 18*0fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticSema.h" 19*0fca6ea1SDimitry Andric #include "clang/Basic/TargetBuiltins.h" 20*0fca6ea1SDimitry Andric #include "clang/Sema/Attr.h" 21*0fca6ea1SDimitry Andric #include "clang/Sema/Sema.h" 22*0fca6ea1SDimitry Andric 23*0fca6ea1SDimitry Andric namespace clang { 24*0fca6ea1SDimitry Andric 25*0fca6ea1SDimitry Andric SemaWasm::SemaWasm(Sema &S) : SemaBase(S) {} 26*0fca6ea1SDimitry Andric 27*0fca6ea1SDimitry Andric /// Checks the argument at the given index is a WebAssembly table and if it 28*0fca6ea1SDimitry Andric /// is, sets ElTy to the element type. 29*0fca6ea1SDimitry Andric static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex, 30*0fca6ea1SDimitry Andric QualType &ElTy) { 31*0fca6ea1SDimitry Andric Expr *ArgExpr = E->getArg(ArgIndex); 32*0fca6ea1SDimitry Andric const auto *ATy = dyn_cast<ArrayType>(ArgExpr->getType()); 33*0fca6ea1SDimitry Andric if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) { 34*0fca6ea1SDimitry Andric return S.Diag(ArgExpr->getBeginLoc(), 35*0fca6ea1SDimitry Andric diag::err_wasm_builtin_arg_must_be_table_type) 36*0fca6ea1SDimitry Andric << ArgIndex + 1 << ArgExpr->getSourceRange(); 37*0fca6ea1SDimitry Andric } 38*0fca6ea1SDimitry Andric ElTy = ATy->getElementType(); 39*0fca6ea1SDimitry Andric return false; 40*0fca6ea1SDimitry Andric } 41*0fca6ea1SDimitry Andric 42*0fca6ea1SDimitry Andric /// Checks the argument at the given index is an integer. 43*0fca6ea1SDimitry Andric static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E, 44*0fca6ea1SDimitry Andric unsigned ArgIndex) { 45*0fca6ea1SDimitry Andric Expr *ArgExpr = E->getArg(ArgIndex); 46*0fca6ea1SDimitry Andric if (!ArgExpr->getType()->isIntegerType()) { 47*0fca6ea1SDimitry Andric return S.Diag(ArgExpr->getBeginLoc(), 48*0fca6ea1SDimitry Andric diag::err_wasm_builtin_arg_must_be_integer_type) 49*0fca6ea1SDimitry Andric << ArgIndex + 1 << ArgExpr->getSourceRange(); 50*0fca6ea1SDimitry Andric } 51*0fca6ea1SDimitry Andric return false; 52*0fca6ea1SDimitry Andric } 53*0fca6ea1SDimitry Andric 54*0fca6ea1SDimitry Andric bool SemaWasm::BuiltinWasmRefNullExtern(CallExpr *TheCall) { 55*0fca6ea1SDimitry Andric if (TheCall->getNumArgs() != 0) 56*0fca6ea1SDimitry Andric return true; 57*0fca6ea1SDimitry Andric 58*0fca6ea1SDimitry Andric TheCall->setType(getASTContext().getWebAssemblyExternrefType()); 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric return false; 61*0fca6ea1SDimitry Andric } 62*0fca6ea1SDimitry Andric 63*0fca6ea1SDimitry Andric bool SemaWasm::BuiltinWasmRefNullFunc(CallExpr *TheCall) { 64*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext(); 65*0fca6ea1SDimitry Andric if (TheCall->getNumArgs() != 0) { 66*0fca6ea1SDimitry Andric Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_many_args) 67*0fca6ea1SDimitry Andric << 0 /*function call*/ << /*expected*/ 0 << TheCall->getNumArgs() 68*0fca6ea1SDimitry Andric << /*is non object*/ 0; 69*0fca6ea1SDimitry Andric return true; 70*0fca6ea1SDimitry Andric } 71*0fca6ea1SDimitry Andric 72*0fca6ea1SDimitry Andric // This custom type checking code ensures that the nodes are as expected 73*0fca6ea1SDimitry Andric // in order to later on generate the necessary builtin. 74*0fca6ea1SDimitry Andric QualType Pointee = Context.getFunctionType(Context.VoidTy, {}, {}); 75*0fca6ea1SDimitry Andric QualType Type = Context.getPointerType(Pointee); 76*0fca6ea1SDimitry Andric Pointee = Context.getAddrSpaceQualType(Pointee, LangAS::wasm_funcref); 77*0fca6ea1SDimitry Andric Type = Context.getAttributedType(attr::WebAssemblyFuncref, Type, 78*0fca6ea1SDimitry Andric Context.getPointerType(Pointee)); 79*0fca6ea1SDimitry Andric TheCall->setType(Type); 80*0fca6ea1SDimitry Andric 81*0fca6ea1SDimitry Andric return false; 82*0fca6ea1SDimitry Andric } 83*0fca6ea1SDimitry Andric 84*0fca6ea1SDimitry Andric /// Check that the first argument is a WebAssembly table, and the second 85*0fca6ea1SDimitry Andric /// is an index to use as index into the table. 86*0fca6ea1SDimitry Andric bool SemaWasm::BuiltinWasmTableGet(CallExpr *TheCall) { 87*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 2)) 88*0fca6ea1SDimitry Andric return true; 89*0fca6ea1SDimitry Andric 90*0fca6ea1SDimitry Andric QualType ElTy; 91*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) 92*0fca6ea1SDimitry Andric return true; 93*0fca6ea1SDimitry Andric 94*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1)) 95*0fca6ea1SDimitry Andric return true; 96*0fca6ea1SDimitry Andric 97*0fca6ea1SDimitry Andric // If all is well, we set the type of TheCall to be the type of the 98*0fca6ea1SDimitry Andric // element of the table. 99*0fca6ea1SDimitry Andric // i.e. a table.get on an externref table has type externref, 100*0fca6ea1SDimitry Andric // or whatever the type of the table element is. 101*0fca6ea1SDimitry Andric TheCall->setType(ElTy); 102*0fca6ea1SDimitry Andric 103*0fca6ea1SDimitry Andric return false; 104*0fca6ea1SDimitry Andric } 105*0fca6ea1SDimitry Andric 106*0fca6ea1SDimitry Andric /// Check that the first argumnet is a WebAssembly table, the second is 107*0fca6ea1SDimitry Andric /// an index to use as index into the table and the third is the reference 108*0fca6ea1SDimitry Andric /// type to set into the table. 109*0fca6ea1SDimitry Andric bool SemaWasm::BuiltinWasmTableSet(CallExpr *TheCall) { 110*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 3)) 111*0fca6ea1SDimitry Andric return true; 112*0fca6ea1SDimitry Andric 113*0fca6ea1SDimitry Andric QualType ElTy; 114*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) 115*0fca6ea1SDimitry Andric return true; 116*0fca6ea1SDimitry Andric 117*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1)) 118*0fca6ea1SDimitry Andric return true; 119*0fca6ea1SDimitry Andric 120*0fca6ea1SDimitry Andric if (!getASTContext().hasSameType(ElTy, TheCall->getArg(2)->getType())) 121*0fca6ea1SDimitry Andric return true; 122*0fca6ea1SDimitry Andric 123*0fca6ea1SDimitry Andric return false; 124*0fca6ea1SDimitry Andric } 125*0fca6ea1SDimitry Andric 126*0fca6ea1SDimitry Andric /// Check that the argument is a WebAssembly table. 127*0fca6ea1SDimitry Andric bool SemaWasm::BuiltinWasmTableSize(CallExpr *TheCall) { 128*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 1)) 129*0fca6ea1SDimitry Andric return true; 130*0fca6ea1SDimitry Andric 131*0fca6ea1SDimitry Andric QualType ElTy; 132*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) 133*0fca6ea1SDimitry Andric return true; 134*0fca6ea1SDimitry Andric 135*0fca6ea1SDimitry Andric return false; 136*0fca6ea1SDimitry Andric } 137*0fca6ea1SDimitry Andric 138*0fca6ea1SDimitry Andric /// Check that the first argument is a WebAssembly table, the second is the 139*0fca6ea1SDimitry Andric /// value to use for new elements (of a type matching the table type), the 140*0fca6ea1SDimitry Andric /// third value is an integer. 141*0fca6ea1SDimitry Andric bool SemaWasm::BuiltinWasmTableGrow(CallExpr *TheCall) { 142*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 3)) 143*0fca6ea1SDimitry Andric return true; 144*0fca6ea1SDimitry Andric 145*0fca6ea1SDimitry Andric QualType ElTy; 146*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) 147*0fca6ea1SDimitry Andric return true; 148*0fca6ea1SDimitry Andric 149*0fca6ea1SDimitry Andric Expr *NewElemArg = TheCall->getArg(1); 150*0fca6ea1SDimitry Andric if (!getASTContext().hasSameType(ElTy, NewElemArg->getType())) { 151*0fca6ea1SDimitry Andric return Diag(NewElemArg->getBeginLoc(), 152*0fca6ea1SDimitry Andric diag::err_wasm_builtin_arg_must_match_table_element_type) 153*0fca6ea1SDimitry Andric << 2 << 1 << NewElemArg->getSourceRange(); 154*0fca6ea1SDimitry Andric } 155*0fca6ea1SDimitry Andric 156*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 2)) 157*0fca6ea1SDimitry Andric return true; 158*0fca6ea1SDimitry Andric 159*0fca6ea1SDimitry Andric return false; 160*0fca6ea1SDimitry Andric } 161*0fca6ea1SDimitry Andric 162*0fca6ea1SDimitry Andric /// Check that the first argument is a WebAssembly table, the second is an 163*0fca6ea1SDimitry Andric /// integer, the third is the value to use to fill the table (of a type 164*0fca6ea1SDimitry Andric /// matching the table type), and the fourth is an integer. 165*0fca6ea1SDimitry Andric bool SemaWasm::BuiltinWasmTableFill(CallExpr *TheCall) { 166*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 4)) 167*0fca6ea1SDimitry Andric return true; 168*0fca6ea1SDimitry Andric 169*0fca6ea1SDimitry Andric QualType ElTy; 170*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, ElTy)) 171*0fca6ea1SDimitry Andric return true; 172*0fca6ea1SDimitry Andric 173*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 1)) 174*0fca6ea1SDimitry Andric return true; 175*0fca6ea1SDimitry Andric 176*0fca6ea1SDimitry Andric Expr *NewElemArg = TheCall->getArg(2); 177*0fca6ea1SDimitry Andric if (!getASTContext().hasSameType(ElTy, NewElemArg->getType())) { 178*0fca6ea1SDimitry Andric return Diag(NewElemArg->getBeginLoc(), 179*0fca6ea1SDimitry Andric diag::err_wasm_builtin_arg_must_match_table_element_type) 180*0fca6ea1SDimitry Andric << 3 << 1 << NewElemArg->getSourceRange(); 181*0fca6ea1SDimitry Andric } 182*0fca6ea1SDimitry Andric 183*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, 3)) 184*0fca6ea1SDimitry Andric return true; 185*0fca6ea1SDimitry Andric 186*0fca6ea1SDimitry Andric return false; 187*0fca6ea1SDimitry Andric } 188*0fca6ea1SDimitry Andric 189*0fca6ea1SDimitry Andric /// Check that the first argument is a WebAssembly table, the second is also a 190*0fca6ea1SDimitry Andric /// WebAssembly table (of the same element type), and the third to fifth 191*0fca6ea1SDimitry Andric /// arguments are integers. 192*0fca6ea1SDimitry Andric bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) { 193*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 5)) 194*0fca6ea1SDimitry Andric return true; 195*0fca6ea1SDimitry Andric 196*0fca6ea1SDimitry Andric QualType XElTy; 197*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 0, XElTy)) 198*0fca6ea1SDimitry Andric return true; 199*0fca6ea1SDimitry Andric 200*0fca6ea1SDimitry Andric QualType YElTy; 201*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsTable(SemaRef, TheCall, 1, YElTy)) 202*0fca6ea1SDimitry Andric return true; 203*0fca6ea1SDimitry Andric 204*0fca6ea1SDimitry Andric Expr *TableYArg = TheCall->getArg(1); 205*0fca6ea1SDimitry Andric if (!getASTContext().hasSameType(XElTy, YElTy)) { 206*0fca6ea1SDimitry Andric return Diag(TableYArg->getBeginLoc(), 207*0fca6ea1SDimitry Andric diag::err_wasm_builtin_arg_must_match_table_element_type) 208*0fca6ea1SDimitry Andric << 2 << 1 << TableYArg->getSourceRange(); 209*0fca6ea1SDimitry Andric } 210*0fca6ea1SDimitry Andric 211*0fca6ea1SDimitry Andric for (int I = 2; I <= 4; I++) { 212*0fca6ea1SDimitry Andric if (CheckWasmBuiltinArgIsInteger(SemaRef, TheCall, I)) 213*0fca6ea1SDimitry Andric return true; 214*0fca6ea1SDimitry Andric } 215*0fca6ea1SDimitry Andric 216*0fca6ea1SDimitry Andric return false; 217*0fca6ea1SDimitry Andric } 218*0fca6ea1SDimitry Andric 219*0fca6ea1SDimitry Andric bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, 220*0fca6ea1SDimitry Andric unsigned BuiltinID, 221*0fca6ea1SDimitry Andric CallExpr *TheCall) { 222*0fca6ea1SDimitry Andric switch (BuiltinID) { 223*0fca6ea1SDimitry Andric case WebAssembly::BI__builtin_wasm_ref_null_extern: 224*0fca6ea1SDimitry Andric return BuiltinWasmRefNullExtern(TheCall); 225*0fca6ea1SDimitry Andric case WebAssembly::BI__builtin_wasm_ref_null_func: 226*0fca6ea1SDimitry Andric return BuiltinWasmRefNullFunc(TheCall); 227*0fca6ea1SDimitry Andric case WebAssembly::BI__builtin_wasm_table_get: 228*0fca6ea1SDimitry Andric return BuiltinWasmTableGet(TheCall); 229*0fca6ea1SDimitry Andric case WebAssembly::BI__builtin_wasm_table_set: 230*0fca6ea1SDimitry Andric return BuiltinWasmTableSet(TheCall); 231*0fca6ea1SDimitry Andric case WebAssembly::BI__builtin_wasm_table_size: 232*0fca6ea1SDimitry Andric return BuiltinWasmTableSize(TheCall); 233*0fca6ea1SDimitry Andric case WebAssembly::BI__builtin_wasm_table_grow: 234*0fca6ea1SDimitry Andric return BuiltinWasmTableGrow(TheCall); 235*0fca6ea1SDimitry Andric case WebAssembly::BI__builtin_wasm_table_fill: 236*0fca6ea1SDimitry Andric return BuiltinWasmTableFill(TheCall); 237*0fca6ea1SDimitry Andric case WebAssembly::BI__builtin_wasm_table_copy: 238*0fca6ea1SDimitry Andric return BuiltinWasmTableCopy(TheCall); 239*0fca6ea1SDimitry Andric } 240*0fca6ea1SDimitry Andric 241*0fca6ea1SDimitry Andric return false; 242*0fca6ea1SDimitry Andric } 243*0fca6ea1SDimitry Andric 244*0fca6ea1SDimitry Andric WebAssemblyImportModuleAttr * 245*0fca6ea1SDimitry Andric SemaWasm::mergeImportModuleAttr(Decl *D, 246*0fca6ea1SDimitry Andric const WebAssemblyImportModuleAttr &AL) { 247*0fca6ea1SDimitry Andric auto *FD = cast<FunctionDecl>(D); 248*0fca6ea1SDimitry Andric 249*0fca6ea1SDimitry Andric if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) { 250*0fca6ea1SDimitry Andric if (ExistingAttr->getImportModule() == AL.getImportModule()) 251*0fca6ea1SDimitry Andric return nullptr; 252*0fca6ea1SDimitry Andric Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) 253*0fca6ea1SDimitry Andric << 0 << ExistingAttr->getImportModule() << AL.getImportModule(); 254*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::note_previous_attribute); 255*0fca6ea1SDimitry Andric return nullptr; 256*0fca6ea1SDimitry Andric } 257*0fca6ea1SDimitry Andric if (FD->hasBody()) { 258*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_import_on_definition) << 0; 259*0fca6ea1SDimitry Andric return nullptr; 260*0fca6ea1SDimitry Andric } 261*0fca6ea1SDimitry Andric return ::new (getASTContext()) 262*0fca6ea1SDimitry Andric WebAssemblyImportModuleAttr(getASTContext(), AL, AL.getImportModule()); 263*0fca6ea1SDimitry Andric } 264*0fca6ea1SDimitry Andric 265*0fca6ea1SDimitry Andric WebAssemblyImportNameAttr * 266*0fca6ea1SDimitry Andric SemaWasm::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) { 267*0fca6ea1SDimitry Andric auto *FD = cast<FunctionDecl>(D); 268*0fca6ea1SDimitry Andric 269*0fca6ea1SDimitry Andric if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) { 270*0fca6ea1SDimitry Andric if (ExistingAttr->getImportName() == AL.getImportName()) 271*0fca6ea1SDimitry Andric return nullptr; 272*0fca6ea1SDimitry Andric Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) 273*0fca6ea1SDimitry Andric << 1 << ExistingAttr->getImportName() << AL.getImportName(); 274*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::note_previous_attribute); 275*0fca6ea1SDimitry Andric return nullptr; 276*0fca6ea1SDimitry Andric } 277*0fca6ea1SDimitry Andric if (FD->hasBody()) { 278*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_import_on_definition) << 1; 279*0fca6ea1SDimitry Andric return nullptr; 280*0fca6ea1SDimitry Andric } 281*0fca6ea1SDimitry Andric return ::new (getASTContext()) 282*0fca6ea1SDimitry Andric WebAssemblyImportNameAttr(getASTContext(), AL, AL.getImportName()); 283*0fca6ea1SDimitry Andric } 284*0fca6ea1SDimitry Andric 285*0fca6ea1SDimitry Andric void SemaWasm::handleWebAssemblyImportModuleAttr(Decl *D, 286*0fca6ea1SDimitry Andric const ParsedAttr &AL) { 287*0fca6ea1SDimitry Andric auto *FD = cast<FunctionDecl>(D); 288*0fca6ea1SDimitry Andric 289*0fca6ea1SDimitry Andric StringRef Str; 290*0fca6ea1SDimitry Andric SourceLocation ArgLoc; 291*0fca6ea1SDimitry Andric if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) 292*0fca6ea1SDimitry Andric return; 293*0fca6ea1SDimitry Andric if (FD->hasBody()) { 294*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_import_on_definition) << 0; 295*0fca6ea1SDimitry Andric return; 296*0fca6ea1SDimitry Andric } 297*0fca6ea1SDimitry Andric 298*0fca6ea1SDimitry Andric FD->addAttr(::new (getASTContext()) 299*0fca6ea1SDimitry Andric WebAssemblyImportModuleAttr(getASTContext(), AL, Str)); 300*0fca6ea1SDimitry Andric } 301*0fca6ea1SDimitry Andric 302*0fca6ea1SDimitry Andric void SemaWasm::handleWebAssemblyImportNameAttr(Decl *D, const ParsedAttr &AL) { 303*0fca6ea1SDimitry Andric auto *FD = cast<FunctionDecl>(D); 304*0fca6ea1SDimitry Andric 305*0fca6ea1SDimitry Andric StringRef Str; 306*0fca6ea1SDimitry Andric SourceLocation ArgLoc; 307*0fca6ea1SDimitry Andric if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) 308*0fca6ea1SDimitry Andric return; 309*0fca6ea1SDimitry Andric if (FD->hasBody()) { 310*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_import_on_definition) << 1; 311*0fca6ea1SDimitry Andric return; 312*0fca6ea1SDimitry Andric } 313*0fca6ea1SDimitry Andric 314*0fca6ea1SDimitry Andric FD->addAttr(::new (getASTContext()) 315*0fca6ea1SDimitry Andric WebAssemblyImportNameAttr(getASTContext(), AL, Str)); 316*0fca6ea1SDimitry Andric } 317*0fca6ea1SDimitry Andric 318*0fca6ea1SDimitry Andric void SemaWasm::handleWebAssemblyExportNameAttr(Decl *D, const ParsedAttr &AL) { 319*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext(); 320*0fca6ea1SDimitry Andric if (!isFuncOrMethodForAttrSubject(D)) { 321*0fca6ea1SDimitry Andric Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) 322*0fca6ea1SDimitry Andric << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; 323*0fca6ea1SDimitry Andric return; 324*0fca6ea1SDimitry Andric } 325*0fca6ea1SDimitry Andric 326*0fca6ea1SDimitry Andric auto *FD = cast<FunctionDecl>(D); 327*0fca6ea1SDimitry Andric if (FD->isThisDeclarationADefinition()) { 328*0fca6ea1SDimitry Andric Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; 329*0fca6ea1SDimitry Andric return; 330*0fca6ea1SDimitry Andric } 331*0fca6ea1SDimitry Andric 332*0fca6ea1SDimitry Andric StringRef Str; 333*0fca6ea1SDimitry Andric SourceLocation ArgLoc; 334*0fca6ea1SDimitry Andric if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) 335*0fca6ea1SDimitry Andric return; 336*0fca6ea1SDimitry Andric 337*0fca6ea1SDimitry Andric D->addAttr(::new (Context) WebAssemblyExportNameAttr(Context, AL, Str)); 338*0fca6ea1SDimitry Andric D->addAttr(UsedAttr::CreateImplicit(Context)); 339*0fca6ea1SDimitry Andric } 340*0fca6ea1SDimitry Andric 341*0fca6ea1SDimitry Andric } // namespace clang 342