diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -697,6 +697,15 @@ static std::vector undefs; +// Check whether the definition name def is a mangled source-name that matches +// the reference name ref, i.e. def is in the form of _Z +// . +static bool canSuggestExternCXX(StringRef ref, StringRef def) { + unsigned len; + return def.consume_front("_Z") && !def.consumeInteger(10, len) && + len == ref.size() && def.take_front(len) == ref; +} + // Suggest an alternative spelling of an "undefined symbol" diagnostic. Returns // the suggested symbol, which is either in the symbol table, or in the same // file of sym. @@ -774,6 +783,19 @@ return s; } } + } else { + const Symbol *s = nullptr; + for (auto &it : map) + if (canSuggestExternCXX(name, it.first)) + s = it.second; + symtab->forEachSymbol([&](Symbol *sym) { + if (canSuggestExternCXX(name, sym->getName())) + s = sym; + }); + if (s) { + hint = "one of the C++ overloads such as "; + return s; + } } return nullptr; diff --git a/lld/test/ELF/undef-suggest-extern-cxx.s b/lld/test/ELF/undef-suggest-extern-cxx.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/undef-suggest-extern-cxx.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o + +## The definition is mangled while the reference is not, suggest an arbitrary +## C++ overload. +# RUN: echo '.globl _Z3fooi; _Z3fooi:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o +# RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s + +## Check that we can suggest a local definition. +# RUN: echo '_Z3fooi: call foo' | llvm-mc -filetype=obj -triple=x86_64 - -o %t2.o +# RUN: not ld.lld %t2.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: foo +# CHECK-NEXT: >>> referenced by {{.*}} +# CHECK-NEXT: >>> did you mean: one of the C++ overloads such as foo(int) + +## Don't suggest nested names whose base name is "foo", e.g. F::foo(). +# RUN: echo '.globl _ZN1F3fooEv; _ZN1F3fooEv:' | llvm-mc -filetype=obj -triple=x86_64 - -o %t3.o +# RUN: not ld.lld %t.o %t3.o -o /dev/null 2>&1 | FileCheck /dev/null --implicit-check-not='did you mean' + +call foo