Index: lld/trunk/COFF/Config.h =================================================================== --- lld/trunk/COFF/Config.h +++ lld/trunk/COFF/Config.h @@ -164,7 +164,7 @@ std::map AlignComm; // Used for /failifmismatch. - std::map MustMatch; + std::map> MustMatch; // Used for /alternatename. std::map AlternateNames; Index: lld/trunk/COFF/Driver.h =================================================================== --- lld/trunk/COFF/Driver.h +++ lld/trunk/COFF/Driver.h @@ -69,7 +69,7 @@ void link(llvm::ArrayRef Args); // Used by the resolver to parse .drectve section contents. - void parseDirectives(StringRef S); + void parseDirectives(InputFile *File); // Used by ArchiveFile to enqueue members. void enqueueArchiveMember(const Archive::Child &C, StringRef SymName, @@ -180,7 +180,7 @@ // if value matches previous values for the key. // This feature used in the directive section to reject // incompatible objects. -void checkFailIfMismatch(StringRef Arg); +void checkFailIfMismatch(StringRef Arg, StringRef Source); // Convert Windows resource files (.res files) to a .obj file. MemoryBufferRef convertResToCOFF(ArrayRef MBs); Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -264,7 +264,13 @@ // Parses .drectve section contents and returns a list of files // specified by /defaultlib. -void LinkerDriver::parseDirectives(StringRef S) { +void LinkerDriver::parseDirectives(InputFile *File) { + StringRef S = File->getDirectives(); + if (S.empty()) + return; + + log("Directives: " + toString(File) + ": " + S); + ArgParser Parser; // .drectve is always tokenized using Windows shell rules. // /EXPORT: option can appear too many times, processing in fastpath. @@ -307,7 +313,7 @@ Config->Entry = addUndefined(mangle(Arg->getValue())); break; case OPT_failifmismatch: - checkFailIfMismatch(Arg->getValue()); + checkFailIfMismatch(Arg->getValue(), toString(File)); break; case OPT_incl: addUndefined(Arg->getValue()); @@ -1271,7 +1277,7 @@ // Handle /failifmismatch for (auto *Arg : Args.filtered(OPT_failifmismatch)) - checkFailIfMismatch(Arg->getValue()); + checkFailIfMismatch(Arg->getValue(), "cmd-line"); // Handle /merge for (auto *Arg : Args.filtered(OPT_merge)) Index: lld/trunk/COFF/DriverUtils.cpp =================================================================== --- lld/trunk/COFF/DriverUtils.cpp +++ lld/trunk/COFF/DriverUtils.cpp @@ -698,16 +698,18 @@ // Parses a string in the form of "key=value" and check // if value matches previous values for the same key. -void checkFailIfMismatch(StringRef Arg) { +void checkFailIfMismatch(StringRef Arg, StringRef Source) { StringRef K, V; std::tie(K, V) = Arg.split('='); if (K.empty() || V.empty()) fatal("/failifmismatch: invalid argument: " + Arg); - StringRef Existing = Config->MustMatch[K]; - if (!Existing.empty() && V != Existing) - fatal("/failifmismatch: mismatch detected: " + Existing + " and " + V + - " for key " + K); - Config->MustMatch[K] = V; + std::pair Existing = Config->MustMatch[K]; + if (!Existing.first.empty() && V != Existing.first) { + fatal("/failifmismatch: mismatch detected for '" + K + "':\n>>> " + + Existing.second + " has value " + Existing.first + "\n>>> " + + Source + " has value " + V); + } + Config->MustMatch[K] = {V, Source}; } // Convert Windows resource files (.res files) to a .obj file. Index: lld/trunk/COFF/SymbolTable.cpp =================================================================== --- lld/trunk/COFF/SymbolTable.cpp +++ lld/trunk/COFF/SymbolTable.cpp @@ -50,12 +50,7 @@ ImportFile::Instances.push_back(F); } - StringRef S = File->getDirectives(); - if (S.empty()) - return; - - log("Directives: " + toString(File) + ": " + S); - Driver->parseDirectives(S); + Driver->parseDirectives(File); } static void errorOrWarn(const Twine &S) { Index: lld/trunk/test/COFF/Inputs/failmismatch1.ll =================================================================== --- lld/trunk/test/COFF/Inputs/failmismatch1.ll +++ lld/trunk/test/COFF/Inputs/failmismatch1.ll @@ -0,0 +1,22 @@ +; ModuleID = 'test.cpp' +source_filename = "test.cpp" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.16.27027" + +; Function Attrs: noinline nounwind optnone sspstrong uwtable +define dso_local i32 @"?f@@YAHXZ"() #0 { + ret i32 0 +} + +attributes #0 = { noinline nounwind optnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.linker.options = !{!0, !1, !2} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = !{!"/DEFAULTLIB:libcmt.lib"} +!1 = !{!"/DEFAULTLIB:oldnames.lib"} +!2 = !{!"/FAILIFMISMATCH:\22TEST=1\22"} +!3 = !{i32 1, !"wchar_size", i32 2} +!4 = !{i32 7, !"PIC Level", i32 2} +!5 = !{!"clang version 7.0.1 (tags/RELEASE_701/final)"} Index: lld/trunk/test/COFF/Inputs/failmismatch2.ll =================================================================== --- lld/trunk/test/COFF/Inputs/failmismatch2.ll +++ lld/trunk/test/COFF/Inputs/failmismatch2.ll @@ -0,0 +1,28 @@ +; ModuleID = 'test2.cpp' +source_filename = "test2.cpp" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.16.27027" + +; Function Attrs: noinline norecurse nounwind optnone sspstrong uwtable +define dso_local i32 @main() #0 { + %1 = alloca i32, align 4 + store i32 0, i32* %1, align 4 + %2 = call i32 @"?f@@YAHXZ"() + ret i32 %2 +} + +declare dso_local i32 @"?f@@YAHXZ"() #1 + +attributes #0 = { noinline norecurse nounwind optnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.linker.options = !{!0, !1, !2} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = !{!"/DEFAULTLIB:libcmt.lib"} +!1 = !{!"/DEFAULTLIB:oldnames.lib"} +!2 = !{!"/FAILIFMISMATCH:\22TEST=2\22"} +!3 = !{i32 1, !"wchar_size", i32 2} +!4 = !{i32 7, !"PIC Level", i32 2} +!5 = !{!"clang version 7.0.1 (tags/RELEASE_701/final)"} Index: lld/trunk/test/COFF/failifmismatch.test =================================================================== --- lld/trunk/test/COFF/failifmismatch.test +++ lld/trunk/test/COFF/failifmismatch.test @@ -1,11 +1,30 @@ -# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ -# RUN: %p/Inputs/ret42.obj +RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ +RUN: %p/Inputs/ret42.obj -# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ -# RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1 +RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ +RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k2=v1 -# RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ -# RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1 +RUN: lld-link /entry:main /subsystem:console /out:%t.exe \ +RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v1 -# RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \ -# RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2 +RUN: not lld-link /entry:main /subsystem:console /out:%t.exe \ +RUN: %p/Inputs/ret42.obj /failifmismatch:k1=v1 /failifmismatch:k1=v2 2>&1 | FileCheck %s + +RUN: llc < %p/Inputs/failmismatch1.ll -filetype obj -o %t1.obj +RUN: llc < %p/Inputs/failmismatch2.ll -filetype obj -o %t2.obj +RUN: not lld-link %t1.obj %t2.obj 2>&1 | FileCheck %s -check-prefix OBJ + +RUN: llvm-lib %t1.obj /out:%t.lib +RUN: not lld-link %t.lib %t2.obj 2>&1 | FileCheck %s -check-prefix LIB + +CHECK: lld-link: error: /failifmismatch: mismatch detected for 'k1': +CHECK-NEXT: >>> cmd-line has value v1 +CHECK-NEXT: >>> cmd-line has value v2 + +OBJ: lld-link: error: /failifmismatch: mismatch detected for 'TEST': +OBJ-NEXT: >>> {{.*}}failifmismatch.test.tmp1.obj has value 1 +OBJ-NEXT: >>> {{.*}}failifmismatch.test.tmp2.obj has value 2 + +LIB: lld-link: error: /failifmismatch: mismatch detected for 'TEST': +LIB-NEXT: >>> {{.*}}failifmismatch.test.tmp2.obj has value 2 +LIB-NEXT: >>> failifmismatch.test.tmp.lib(failifmismatch.test.tmp1.obj) has value 1