summaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2018-12-21 19:28:49 +0000
committerRui Ueyama <ruiu@google.com>2018-12-21 19:28:49 +0000
commit393dd6c0ce18f225471799cd133fc8deaf918021 (patch)
tree5318939e0a8be6b74641e1edb4cc9b2c25d1ca07 /lld
parenta8165a98cdfe3bae03206208969f42df82be22d4 (diff)
Add a doc for missing key function and an error message referencing the doc.
Summary: This is a common error, and because many people don't know what the key function is, it is sometimes very confusing. The doc was originally written by Brooks Moses and slightly edited by me. Reviewers: MaskRay, espindola Subscribers: emaste, llvm-commits, arichardson Differential Revision: https://reviews.llvm.org/D55968
Diffstat (limited to 'lld')
-rw-r--r--lld/ELF/Relocations.cpp4
-rw-r--r--lld/docs/missingkeymethod.rst84
-rw-r--r--lld/test/ELF/undef.s4
3 files changed, 92 insertions, 0 deletions
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index e01fdd2ee0d..57a43977101 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -663,6 +663,10 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
Msg += Src + "\n>>> ";
Msg += Sec.getObjMsg(Offset);
+ if (Sym.getName().startswith("_ZTV"))
+ Msg += "\nthe vtable symbol may be undefined because the class is missing "
+ "its key function (see https://lld.llvm.org/missingkeymethod)";
+
if ((Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) ||
Config->NoinhibitExec) {
warn(Msg);
diff --git a/lld/docs/missingkeymethod.rst b/lld/docs/missingkeymethod.rst
new file mode 100644
index 00000000000..3958cc1359c
--- /dev/null
+++ b/lld/docs/missingkeymethod.rst
@@ -0,0 +1,84 @@
+Missing Key Method
+==================
+
+If your build failed with a linker error something like this::
+
+ foo.cc:28: error: undefined reference to 'vtable for C'
+ the vtable symbol may be undefined because the class is missing its key function (see https://lld.llvm.org/missingkeymethod)
+
+it's likely that your class C has a key method (defined by the ABI as the first
+non-pure, non-inline, virtual method), but you haven't actually defined it.
+
+When a class has a key method, the compiler emits the vtable (and some other
+things as well) only in the translation unit that defines that key method. Thus,
+if you're missing the key method, you'll also be missing the vtable. If no other
+function calls your missing method, you won't see any undefined reference errors
+for it, but you will see undefined references to the vtable symbol.
+
+When a class has no non-pure, non-inline, virtual methods, there is no key
+method, and the compiler is forced to emit the vtable in every translation unit
+that references the class. In this case, it is emitted in a COMDAT section,
+which allows the linker to eliminate all duplicate copies. This is still
+wasteful in terms of object file size and link time, so it's always advisable to
+ensure there is at least one eligible method that can serve as the key method.
+
+Here are the most common mistakes that lead to this error:
+
+Failing to define a virtual destructor
+--------------------------------------
+
+Say you have a base class declared in a header file::
+
+ class B {
+ public:
+ B();
+ virtual ~B();
+ ...
+ };
+
+Here, ``~B`` is the first non-pure, non-inline, virtual method, so it is the key
+method. If you forget to define ``B::~B`` in your source file, the compiler will
+not emit the vtable for ``B``, and you'll get an undefined reference to "vtable
+for B".
+
+This is just an example of the more general mistake of forgetting to define the
+key method, but it's quite common because virtual destructors are likely to be
+the first eligible key method and it's easy to forget to implement them. It's
+also more likely that you won't have any direct references to the destructor, so
+you won't see any undefined reference errors that point directly to the problem.
+
+The solution in this case is to implement the missing method.
+
+Forgetting to declare a virtual method in an abstract class as pure
+-------------------------------------------------------------------
+
+Say you have an abstract base class declared in a header file::
+
+ class A {
+ public:
+ A();
+ virtual ~A() {}
+ virtual int foo() = 0;
+ ...
+ virtual int bar();
+ ...
+ };
+
+This base class is intended to be abstract, but you forgot to mark one of the
+methods pure. Here, ``A::bar``, being non-pure, is nominated as the key method,
+and as a result, the vtable for ``A`` is not emitted, because the compiler is
+waiting for a translation unit that defines ``A::bar``.
+
+The solution in this case is to add the missing ``= 0`` to the declaration of
+``A::bar``.
+
+Key method is defined, but the linker doesn't see it
+----------------------------------------------------
+
+It's also possible that you have defined the key method somewhere, but the
+object file containing the definition of that method isn't being linked into
+your application.
+
+The solution in this case is to check your dependencies to make sure that
+the object file or the library file containing the key method is given to
+the linker.
diff --git a/lld/test/ELF/undef.s b/lld/test/ELF/undef.s
index a511723394d..6fef015f230 100644
--- a/lld/test/ELF/undef.s
+++ b/lld/test/ELF/undef.s
@@ -20,6 +20,9 @@
# CHECK: >>> referenced by undef.s
# CHECK: >>> {{.*}}:(.text+0x10)
+# CHECK: error: undefined symbol: vtable for Foo
+# CHECK: the vtable symbol may be undefined because the class is missing its key function (see https://lld.llvm.org/missingkeymethod)
+
# CHECK: error: undefined symbol: zed2
# CHECK: >>> referenced by {{.*}}.o:(.text+0x0) in archive {{.*}}2.a
@@ -60,3 +63,4 @@ _start:
call bar
call zed1
call _Z3fooi
+ call _ZTV3Foo