Index: test/wasm/demangle.ll =================================================================== --- test/wasm/demangle.ll +++ test/wasm/demangle.ll @@ -1,17 +1,19 @@ ; RUN: llc -filetype=obj %s -o %t.o -; RUN: not wasm-ld --undefined _Z3fooi \ -; RUN: -o %t.wasm %t.o 2>&1 | FileCheck %s +; RUN: not wasm-ld -o %t.wasm %t.o 2>&1 | FileCheck %s -; CHECK: error: undefined symbol: foo(int) +; CHECK: error: {{.*}}.o: undefined symbol: foo(int) -; RUN: not wasm-ld --no-demangle --undefined _Z3fooi \ -; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s +; RUN: not wasm-ld --no-demangle \ +; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s -; CHECK-NODEMANGLE: error: undefined symbol: _Z3fooi +; CHECK-NODEMANGLE: error: {{.*}}.o: undefined symbol: _Z3fooi target triple = "wasm32-unknown-unknown" +declare void @_Z3fooi(i32); + define hidden void @_start() local_unnamed_addr { entry: + call void @_Z3fooi(i32 1) ret void } Index: test/wasm/load-undefined.test =================================================================== --- test/wasm/load-undefined.test +++ test/wasm/load-undefined.test @@ -33,9 +33,6 @@ ; NO-LOAD-NEXT: Name: ret64 ; NO-LOAD-NEXT: ... -; Verify that referencing a symbol that doesn't exist won't work -; RUN: not wasm-ld %t.start.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s -; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist - -; RUN: not wasm-ld %t.start.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s -; CHECK-UNDEFINED2: symbol forced with --undefined not found: symboldoesnotexist +; Verify that referencing a symbol that is not found doesn't result in a link +; failure. This matches the behaviour of the ELF linker. +; RUN: wasm-ld %t.start.o -o %t.wasm -u symboldoesnotexist Index: test/wasm/undefined-entry.test =================================================================== --- test/wasm/undefined-entry.test +++ test/wasm/undefined-entry.test @@ -1,11 +1,9 @@ RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o RUN: not wasm-ld -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s +RUN: not wasm-ld --allow-undefined -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s RUN: not wasm-ld -entry=foo -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-CUSTOM -RUN: not wasm-ld --allow-undefined -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-ALLOW -CHECK: error: undefined symbol: _start -CHECK-CUSTOM: error: undefined symbol: foo -CHECK-ALLOW: error: entry symbol not defined (pass --no-entry to supress): -_start +CHECK: error: entry symbol not defined (pass --no-entry to supress): _start +CHECK-CUSTOM: error: entry symbol not defined (pass --no-entry to supress): foo RUN: wasm-ld --no-entry -o %t.wasm %t.ret32.o Index: test/wasm/undefined.ll =================================================================== --- test/wasm/undefined.ll +++ test/wasm/undefined.ll @@ -1,10 +1,10 @@ ; RUN: llc -filetype=obj %s -o %t.o ; RUN: wasm-ld --allow-undefined -o %t.wasm %t.o -; Fails due to undefined 'foo' and also 'baz' +; Fails due to undefined 'foo' ; RUN: not wasm-ld --undefined=baz -o %t.wasm %t.o 2>&1 | FileCheck %s ; CHECK: error: {{.*}}.o: undefined symbol: foo -; CHECK: error: undefined symbol: baz +; CHECK-NOT: undefined symbol: baz ; Succeeds if we pass a file containing 'foo' as --allow-undefined-file. ; RUN: echo 'foo' > %t.txt Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -505,23 +505,16 @@ return; // Make sure we have resolved all symbols. - if (!Config->Relocatable && !Config->AllowUndefined) { + if (!Config->Relocatable && !Config->AllowUndefined) Symtab->reportRemainingUndefines(); - } else { - // Even when using --allow-undefined we still want to report the absence of - // our initial set of undefined symbols (i.e. the entry point and symbols - // specified via --undefined). - // Part of the reason for this is that these function don't have signatures - // so which means they cannot be written as wasm function imports. - for (auto *Arg : Args.filtered(OPT_undefined)) { - Symbol *Sym = Symtab->find(Arg->getValue()); - if (!Sym->isDefined()) - error("symbol forced with --undefined not found: " + Sym->getName()); - } - if (EntrySym && !EntrySym->isDefined()) - error("entry symbol not defined (pass --no-entry to supress): " + - EntrySym->getName()); - } + + // Handle entry point specially since reportRemainingUndefines() won't + // report errors for symbols that don't come from files (e.g. --undefined or + // the entry symbol). + if (EntrySym && !EntrySym->isDefined()) + error("entry symbol not defined (pass --no-entry to supress): " + + EntrySym->getName()); + if (errorCount()) return; Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -60,7 +60,6 @@ } void SymbolTable::reportRemainingUndefines() { - SetVector Undefs; for (Symbol *Sym : SymVector) { if (!Sym->isUndefined() || Sym->isWeak()) continue; @@ -68,20 +67,12 @@ continue; if (!Sym->IsUsedInRegularObj) continue; - Undefs.insert(Sym); - } - - if (Undefs.empty()) - return; - - for (ObjFile *File : ObjectFiles) - for (Symbol *Sym : File->getSymbols()) - if (Undefs.count(Sym)) - error(toString(File) + ": undefined symbol: " + toString(*Sym)); - - for (Symbol *Sym : Undefs) + // Don't report undefined symbols that came from --undefined flag + // rather than from an actual file. if (!Sym->getFile()) - error("undefined symbol: " + toString(*Sym)); + continue; + error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym)); + } } Symbol *SymbolTable::find(StringRef Name) { Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -845,8 +845,10 @@ } for (const Symbol *Sym : ImportedSymbols) - if (auto *F = dyn_cast(Sym)) + if (auto *F = dyn_cast(Sym)) { + assert(F->FunctionType != nullptr); registerType(*F->FunctionType); + } for (const InputFunction *F : InputFunctions) registerType(F->Signature);