Index: test/wasm/Inputs/ret32.ll =================================================================== --- test/wasm/Inputs/ret32.ll +++ test/wasm/Inputs/ret32.ll @@ -1,7 +1,7 @@ target triple = "wasm32-unknown-unknown" ; Function Attrs: norecurse nounwind readnone -define i32 @ret32(float %arg) #0 { +define hidden i32 @ret32(float %arg) #0 { entry: ret i32 0 ; ptrtoint (i32 (float)* @ret32 to i32) Index: test/wasm/Inputs/ret64.ll =================================================================== --- test/wasm/Inputs/ret64.ll +++ test/wasm/Inputs/ret64.ll @@ -1,6 +1,6 @@ target triple = "wasm32-unknown-unknown" -define i64 @ret64(double %arg) local_unnamed_addr #0 { +define hidden i64 @ret64(double %arg) local_unnamed_addr #0 { entry: ret i64 1 } Index: test/wasm/fatal-warnings.ll =================================================================== --- test/wasm/fatal-warnings.ll +++ test/wasm/fatal-warnings.ll @@ -9,6 +9,11 @@ target triple = "wasm32-unknown-unknown" define hidden void @_start() local_unnamed_addr #0 { +entry: + ret void +} + +define hidden void @_call_ret32() local_unnamed_addr #0 { entry: %call = tail call i32 @ret32(i32 1, i64 2, i32 3) #2 ret void Index: test/wasm/load-undefined.test =================================================================== --- test/wasm/load-undefined.test +++ test/wasm/load-undefined.test @@ -5,31 +5,32 @@ ; RUN: llc -filetype=obj %S/Inputs/ret32.ll -o %t2.o ; RUN: llc -filetype=obj %S/Inputs/start.ll -o %t.start.o ; RUN: llvm-ar rcs %t2.a %t2.o -; RUN: wasm-ld %t.start.o %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64 +; RUN: wasm-ld %t.start.o --no-gc-sections %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64 ; RUN: obj2yaml %t.wasm | FileCheck %s +; RUN: wasm-ld %t.start.o --no-gc-sections %t2.a %t.o -o %t2.wasm +; RUN: obj2yaml %t2.wasm | FileCheck %s -check-prefix=NO-LOAD -; CHECK: - Type: EXPORT -; CHECK-NEXT: Exports: -; CHECK-NEXT: - Name: memory -; CHECK-NEXT: Kind: MEMORY -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: __heap_base -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: __data_end -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: ret32 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: ret64 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 -; CHECK-NEXT: - Type: +; CHECK: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: ret32 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: ret64 +; CHECK-NEXT: ... +; NO-LOAD: Name: name +; NO-LOAD-NEXT: FunctionNames: +; NO-LOAD-NEXT: - Index: 0 +; NO-LOAD-NEXT: Name: __wasm_call_ctors +; NO-LOAD-NEXT: - Index: 1 +; NO-LOAD-NEXT: Name: _start +; NO-LOAD-NEXT: - Index: 2 +; 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 Index: test/wasm/signature-mismatch-weak.ll =================================================================== --- test/wasm/signature-mismatch-weak.ll +++ test/wasm/signature-mismatch-weak.ll @@ -1,7 +1,7 @@ ; RUN: llc -filetype=obj %p/Inputs/weak-symbol1.ll -o %t.weak.o ; RUN: llc -filetype=obj %p/Inputs/strong-symbol.ll -o %t.strong.o ; RUN: llc -filetype=obj %s -o %t.o -; RUN: wasm-ld -o %t.wasm %t.o %t.strong.o %t.weak.o 2>&1 | FileCheck %s +; RUN: not wasm-ld -o %t.wasm %t.o %t.strong.o %t.weak.o 2>&1 | FileCheck %s target triple = "wasm32-unknown-unknown" @@ -16,3 +16,4 @@ ; CHECK: warning: function signature mismatch: weakFn ; CHECK-NEXT: >>> defined as () -> I32 in {{.*}}signature-mismatch-weak.ll.tmp.o ; CHECK-NEXT: >>> defined as () -> I64 in {{.*}}signature-mismatch-weak.ll.tmp.strong.o +; CHECK: error: function signature mismatch: weakFn Index: test/wasm/signature-mismatch.ll =================================================================== --- test/wasm/signature-mismatch.ll +++ test/wasm/signature-mismatch.ll @@ -1,10 +1,11 @@ ; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o ; RUN: llc -filetype=obj %s -o %t.main.o -; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s +; RUN: not wasm-ld -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s +; RUN: not wasm-ld --no-gc-sections -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=NO-GC ; Run the test again by with the object files in the other order to verify ; the check works when the undefined symbol is resolved by an existing defined ; one. -; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.ret32.o %t.main.o 2>&1 | FileCheck %s -check-prefix=REVERSE +; RUN: not wasm-ld -o %t.wasm %t.ret32.o %t.main.o 2>&1 | FileCheck %s -check-prefix=REVERSE target triple = "wasm32-unknown-unknown" @@ -17,10 +18,16 @@ declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1 -; CHECK: error: function signature mismatch: ret32 +; CHECK: warning: function signature mismatch: ret32 ; CHECK-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o ; CHECK-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o +; CHECK: error: function signature mismatch: ret32 -; REVERSE: error: function signature mismatch: ret32 +; NO-GC: error: function signature mismatch: ret32 +; NO-GC-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o +; NO-GC-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o + +; REVERSE: warning: function signature mismatch: ret32 ; REVERSE-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o ; REVERSE-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o +; REVERSE: error: function signature mismatch: ret32 Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -483,7 +483,8 @@ return; // Do size optimizations: garbage collection - markLive(); + if (Config->GcSections) + markLive(); // Write the result to the file. writeResult(); Index: wasm/MarkLive.cpp =================================================================== --- wasm/MarkLive.cpp +++ wasm/MarkLive.cpp @@ -34,9 +34,6 @@ using namespace lld::wasm; void lld::wasm::markLive() { - if (!Config->GcSections) - return; - LLVM_DEBUG(dbgs() << "markLive\n"); SmallVector Q; @@ -45,6 +42,8 @@ return; LLVM_DEBUG(dbgs() << "markLive: " << Sym->getName() << "\n"); Sym->markLive(); + if (Sym->SignatureMismatch) + error("function signature mismatch: " + Sym->getName()); if (InputChunk *Chunk = Sym->getChunk()) Q.push_back(Chunk); }; Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -106,7 +106,7 @@ " in " + toString(File)); } -static void checkFunctionType(const Symbol *Existing, const InputFile *File, +static void checkFunctionType(Symbol *Existing, const InputFile *File, const WasmSignature *NewSig) { auto ExistingFunction = dyn_cast(Existing); if (!ExistingFunction) { @@ -114,12 +114,27 @@ return; } + // Don't generate more than one warning per symbol. + if (Existing->SignatureMismatch) + return; + const WasmSignature *OldSig = ExistingFunction->getFunctionType(); if (OldSig && NewSig && *NewSig != *OldSig) { - warn("function signature mismatch: " + Existing->getName() + - "\n>>> defined as " + toString(*OldSig) + " in " + - toString(Existing->getFile()) + "\n>>> defined as " + - toString(*NewSig) + " in " + toString(File)); + std::string msg = ("function signature mismatch: " + Existing->getName() + + "\n>>> defined as " + toString(*OldSig) + " in " + + toString(Existing->getFile()) + "\n>>> defined as " + + toString(*NewSig) + " in " + toString(File)) + .str(); + // A function signature mismatch is only really problem if the mismatched + // symbol is included in the final output, and gc-sections can remove the + // offending uses. Therefore we delay reporting this as an error when + // section GC is enabled. + if (Config->GcSections) { + Existing->SignatureMismatch = true; + warn(msg); + } else { + error(msg); + } } } Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -93,11 +93,12 @@ // True if this symbol was referenced by a regular (non-bitcode) object. unsigned IsUsedInRegularObj : 1; + unsigned SignatureMismatch : 1; protected: Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) - : IsUsedInRegularObj(false), Name(Name), SymbolKind(K), Flags(Flags), - File(F), Referenced(!Config->GcSections) {} + : IsUsedInRegularObj(false), SignatureMismatch(false), Name(Name), + SymbolKind(K), Flags(Flags), File(F), Referenced(!Config->GcSections) {} StringRef Name; Kind SymbolKind; @@ -340,6 +341,7 @@ T *S2 = new (S) T(std::forward(Arg)...); S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj; + S2->SignatureMismatch = SymCopy.SignatureMismatch; return S2; }