New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 623844 link

Starred by 1 user

Issue metadata

Status: ExternalDependency
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 3
Type: Bug



Sign in to add a comment

Unresolved reference to implicitly generated move constructor (MSVC) or `= default` methods (clang,gcc) when using explicit template instantiation (compiler bugs)

Project Member Reported by tapted@chromium.org, Jun 28 2016

Issue description

Chrome Version       : 53.0.2774.3

I tried making event_with_latency_info.h use extern templates and ran into a couple of compiler bugs. Found a decent workaround though.

Context: https://codereview.chromium.org/2091213002/
Goal: Encapsulate definitions for `CanCoalesceWith` and `CoalesceWith`

https://codereview.chromium.org/2091213002/#ps120001 should have worked, but the build fails on the component build in win_chromium_compile_dbg_ng with

[18246/18288] LINK content_unittests.exe
FAILED: content_unittests.exe 
E:/b/depot_tools/python276_bin/python.exe gyp-win-tool link-wrapper environment.x86 False link.exe /nologo /OUT:content_unittests.exe /PDB:content_unittests.exe.pdb @content_unittests.exe.rsp
event_with_latency_info_unittest.obj :error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall content::EventWithLatencyInfo<class blink::WebGestureEvent>::EventWithLatencyInfo<class blink::WebGestureEvent>(class content::EventWithLatencyInfo<class blink::WebGestureEvent> &&)" (__imp_??0?$EventWithLatencyInfo@VWebGestureEvent@blink@@@content@@QAE@$$QAV01@@Z) referenced in function "protected: class content::EventWithLatencyInfo<class blink::WebGestureEvent> __thiscall content::`anonymous namespace'::EventWithLatencyInfoTest::CreateGestureEvent(enum blink::WebInputEvent::Type,double)" (?CreateGestureEvent@EventWithLatencyInfoTest@?A0x58bef626@content@@IAE?AV?$EventWithLatencyInfo@VWebGestureEvent@blink@@@3@W4Type@WebInputEvent@blink@@N@Z)
event_with_latency_info_unittest.obj :error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall content::EventWithLatencyInfo<class blink::WebMouseWheelEvent>...
event_with_latency_info_unittest.obj :error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall content::EventWithLatencyInfo<class blink::WebMouseEvent>...
event_with_latency_info_unittest.obj :error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall content::EventWithLatencyInfo<class blink::WebTouchEvent>...
content_unittests.exe : fatalerror LNK1120: 4 unresolved externals

Note these are the *move* constructors. They're being used for NVRO in event_with_latency_info_unittest.cc which has code like

  MouseEventWithLatencyInfo CreateMouseEvent(WebInputEvent::Type type,
                                             double timestamp) {
    MouseEventWithLatencyInfo mouse;
    mouse.event.type = type;
    mouse.event.timeStampSeconds = timestamp;
    return mouse;
  }

I seem to recall the standards committee deciding that there would be no implicitly generated move constructors, so it's probably a bug that NVRO there tries to use it. But, we can resolve this by just declaring a move constructor (and the rest so they aren't hidden by the move constructor):

  EventWithLatencyInfo(const EventWithLatencyInfo& other) = default;
  EventWithLatencyInfo(EventWithLatencyInfo&& other) = default;
  EventWithLatencyInfo& operator=(const EventWithLatencyInfo& other) = default;


But! Although this fixed Windows, it caused other platforms to fail in https://codereview.chromium.org/2091213002/#ps220001

Errors like

[5056/5365] LINK ./components_unittests
FAILED: components_unittests 
TOOL_VERSION=1465060049 ../../build/toolchain/mac/linker_driver.py /b/build/slave/cache/cipd/goma/gomacc ../../third_party/llvm-build/Release+Asserts/bin/clang++  -stdlib=libc++ /* snip */
Undefined symbols for architecture x86_64:
  "content::EventWithLatencyInfo<blink::WebMouseEvent>::operator=(content::EventWithLatencyInfo<blink::WebMouseEvent> const&)", referenced from:
      content::InputRouterImpl::SendMouseEventImmediately(content::EventWithLatencyInfo<blink::WebMouseEvent> const&) in input_router_impl.o
      content::TouchpadTapSuppressionController::ShouldDeferMouseDown(content::EventWithLatencyInfo<blink::WebMouseEvent> const&) in touchpad_tap_suppression_controller.o
  "content::EventWithLatencyInfo<blink::WebTouchEvent>::operator=(content::EventWithLatencyInfo<blink::WebTouchEvent> const&)", referenced from:
      content::TouchEventQueue::ForwardNextEventToRenderer() in touch_event_queue.o
      content::TouchEventQueue::TouchTimeoutHandler::StartIfNecessary(content::EventWithLatencyInfo<blink::WebTouchEvent> const&) in touch_event_queue.o
  "content::EventWithLatencyInfo<blink::WebGestureEvent>::operator=(content::EventWithLatencyInfo<blink::WebGestureEvent> const&)", referenced from:
      content::GestureEventQueue::QueueScrollOrPinchAndForwardIfNecessary(content::EventWithLatencyInfo<blink::WebGestureEvent> const&) in gesture_event_queue.o
      content::GestureEventQueue::ProcessGestureAck(content::InputEventAckState, blink::WebInputEvent::Type, ui::LatencyInfo const&) in gesture_event_queue.o
      std::__1::/* snip */

The bug here seems to be that the explicit instantiation of an extern template doesn't generate any code for `= default` methods. There's a gcc bug filed already here - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51629 . Couldn't find a clang bug for it. But since only Windows needs the `= default` thing they can just be put behind guards.

A basic test case goes like:

$ head -n100 e.h e.cc extern_default.cc build.sh
==> e.h <==
class I {
 public:
  I() {}
  I& operator=(const I&);
};

template <class T>
class E {
 public:
  T t;
  E() : t() {}
  E& operator=(const E&) = default;
};

extern template class E<I>;

==> e.cc <==
#include "e.h"

I& I::operator=(const I& i) { return *this; }

template class E<I>;

==> extern_default.cc <==
#include "e.h"

int main() {
  E<I> e1, e2;
  e1 = e2;
}

==> build.sh <==
g++ extern_default.cc e.cc -Wall -std=c++11

$ bash build.sh
Undefined symbols for architecture x86_64:
  "E<I>::operator=(E<I> const&)", referenced from:
      _main in extern_default-66fb4a.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

$ nm e.o | c++filt
0000000000000060 S E<I>::E()
0000000000000020 S E<I>::E()
0000000000000040 S I::I()
0000000000000080 S I::I()
0000000000000000 T I::operator=(I const&)


Filing this to track, and cc some people who might care about it (or see an alternative diagnosis). Still need to hunt down (or file) a clang version of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51629, and put together a test case for MSVC.
 
extern_default.tar.gz
421 bytes Download

Comment 1 by thakis@chromium.org, Jun 28 2016

My advise wrt exported templates remains "don't", it's just a huge headache, and while you might get it to work somehow, it'll be hard to understand and change for others.
(to close the loop here, to satisfy the original goal we went with https://codereview.chromium.org/2111593003 - basically just use function overrides - forward declare (and export) them in the header so that the template definition can stay in the header as well.)

Sign in to add a comment