[LLD][COFF] More detailed information for /failifmismatch

When mismatched #pragma detect_mismatch declarations occur, now print the conflicting OBJs.

  lld-link: error: /failifmismatch: mismatch detected for 'TEST':
  >>> test.obj has value 1
  >>> test2.obj has value 2

Fixes PR38579

Differential Revision: https://reviews.llvm.org/D58910

llvm-svn: 355543
This commit is contained in:
Alexandre Ganea 2019-03-06 20:18:38 +00:00
parent 05efe0fdc4
commit d8ec81059e
8 changed files with 98 additions and 26 deletions

View file

@ -164,7 +164,7 @@ struct Configuration {
std::map<std::string, int> AlignComm;
// Used for /failifmismatch.
std::map<StringRef, StringRef> MustMatch;
std::map<StringRef, std::pair<StringRef, std::string>> MustMatch;
// Used for /alternatename.
std::map<StringRef, StringRef> AlternateNames;

View file

@ -264,7 +264,13 @@ static bool isDecorated(StringRef Sym) {
// 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 @@ void LinkerDriver::parseDirectives(StringRef S) {
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 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// 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))

View file

@ -69,7 +69,7 @@ public:
void link(llvm::ArrayRef<const char *> 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 @@ void assignExportOrdinals();
// 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<MemoryBufferRef> MBs);

View file

@ -698,16 +698,18 @@ void assignExportOrdinals() {
// 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<StringRef, StringRef> 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.

View file

@ -50,12 +50,7 @@ void SymbolTable::addFile(InputFile *File) {
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) {

View file

@ -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)"}

View file

@ -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)"}

View file

@ -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