blob: e743e1936f7a5a94338f0158be3f2d77899abd2e [file] [log] [blame]
mdempskyfba51c12016-02-09 14:41:47 +09001// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef IPC_EXPORT_TEMPLATE_H_
6#define IPC_EXPORT_TEMPLATE_H_
7
8// Synopsis
9//
10// This header provides macros for using FOO_EXPORT macros with explicit
11// template instantiation declarations and definitions.
12// Generally, the FOO_EXPORT macros are used at declarations,
13// and GCC requires them to be used at explicit instantiation declarations,
14// but MSVC requires __declspec(dllexport) to be used at the explicit
15// instantiation definitions instead.
16
17// Usage
18//
19// In a header file, write:
20//
21// extern template class EXPORT_TEMPLATE_DECLARE(FOO_EXPORT) foo<bar>;
22//
23// In a source file, write:
24//
25// template class EXPORT_TEMPLATE_DEFINE(FOO_EXPORT) foo<bar>;
26
27// Implementation notes
28//
29// The implementation of this header uses some subtle macro semantics to
30// detect what the provided FOO_EXPORT value was defined as and then
31// to dispatch to appropriate macro definitions. Unfortunately,
32// MSVC's C preprocessor is rather non-compliant and requires special
33// care to make it work.
34//
35// Issue 1.
36//
37// #define F(x)
38// F()
39//
40// MSVC emits warning C4003 ("not enough actual parameters for macro
41// 'F'), even though it's a valid macro invocation. This affects the
42// macros below that take just an "export" parameter, because export
43// may be empty.
44//
45// As a workaround, we can add a dummy parameter and arguments:
46//
47// #define F(x,_)
48// F(,)
49//
50// Issue 2.
51//
52// #define F(x) G##x
53// #define Gj() ok
54// F(j())
55//
56// The correct replacement for "F(j())" is "ok", but MSVC replaces it
57// with "Gj()". As a workaround, we can pass the result to an
58// identity macro to force MSVC to look for replacements again. (This
59// is why EXPORT_TEMPLATE_STYLE_3 exists.)
60
61#define EXPORT_TEMPLATE_DECLARE(export) \
62 EXPORT_TEMPLATE_INVOKE(DECLARE, EXPORT_TEMPLATE_STYLE(export, ), export)
63#define EXPORT_TEMPLATE_DEFINE(export) \
64 EXPORT_TEMPLATE_INVOKE(DEFINE, EXPORT_TEMPLATE_STYLE(export, ), export)
65
66// INVOKE is an internal helper macro to perform parameter replacements
67// and token pasting to chain invoke another macro. E.g.,
68// EXPORT_TEMPLATE_INVOKE(DECLARE, DEFAULT, FOO_EXPORT)
69// will export to call
70// EXPORT_TEMPLATE_DECLARE_DEFAULT(FOO_EXPORT, )
71// (but with FOO_EXPORT expanded too).
72#define EXPORT_TEMPLATE_INVOKE(which, style, export) \
73 EXPORT_TEMPLATE_INVOKE_2(which, style, export)
74#define EXPORT_TEMPLATE_INVOKE_2(which, style, export) \
75 EXPORT_TEMPLATE_##which##_##style(export, )
76
77// Default style is to apply the FOO_EXPORT macro at declaration sites.
78#define EXPORT_TEMPLATE_DECLARE_DEFAULT(export, _) export
79#define EXPORT_TEMPLATE_DEFINE_DEFAULT(export, _)
80
81// The "MSVC hack" style is used when FOO_EXPORT is defined
82// as __declspec(dllexport), which MSVC requires to be used at
83// definition sites instead.
84#define EXPORT_TEMPLATE_DECLARE_MSVC_HACK(export, _)
85#define EXPORT_TEMPLATE_DEFINE_MSVC_HACK(export, _) export
86
87// EXPORT_TEMPLATE_STYLE is an internal helper macro that identifies which
88// export style needs to be used for the provided FOO_EXPORT macro definition.
89// "", "__attribute__(...)", and "__declspec(dllimport)" are mapped
90// to "DEFAULT"; while "__declspec(dllexport)" is mapped to "MSVC_HACK".
91//
92// It's implemented with token pasting to transform the __attribute__ and
93// __declspec annotations into macro invocations. E.g., if FOO_EXPORT is
94// defined as "__declspec(dllimport)", it undergoes the following sequence of
95// macro substitutions:
96// EXPORT_TEMPLATE_STYLE(FOO_EXPORT, )
97// EXPORT_TEMPLATE_STYLE_2(__declspec(dllimport), )
98// EXPORT_TEMPLATE_STYLE_3(EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport))
99// EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport)
100// EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport
101// DEFAULT
102#define EXPORT_TEMPLATE_STYLE(export, _) EXPORT_TEMPLATE_STYLE_2(export, )
103#define EXPORT_TEMPLATE_STYLE_2(export, _) \
104 EXPORT_TEMPLATE_STYLE_3( \
105 EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA##export)
106#define EXPORT_TEMPLATE_STYLE_3(style) style
107
108// Internal helper macros for EXPORT_TEMPLATE_STYLE.
109//
110// XXX: C++ reserves all identifiers containing "__" for the implementation,
111// but "__attribute__" and "__declspec" already contain "__" and the token-paste
112// operator can only add characters; not remove them. To minimize the risk of
113// conflict with implementations, we include "foj3FJo5StF0OvIzl7oMxA" (a random
114// 128-bit string, encoded in Base64) in the macro name.
115#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA DEFAULT
116#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__attribute__(...) \
117 DEFAULT
118#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__declspec(arg) \
119 EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_##arg
120
121// Internal helper macros for EXPORT_TEMPLATE_STYLE.
122#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllexport MSVC_HACK
123#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport DEFAULT
124
125// Sanity checks.
126//
127// EXPORT_TEMPLATE_TEST uses the same macro invocation pattern as
128// EXPORT_TEMPLATE_DECLARE and EXPORT_TEMPLATE_DEFINE do to check that they're
129// working correctly. When they're working correctly, the sequence of macro
130// replacements should go something like:
131//
132// EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport));
133//
134// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT,
135// EXPORT_TEMPLATE_STYLE(__declspec(dllimport), ),
136// __declspec(dllimport)), "__declspec(dllimport)");
137//
138// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT,
139// DEFAULT, __declspec(dllimport)), "__declspec(dllimport)");
140//
141// static_assert(EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(
142// __declspec(dllimport)), "__declspec(dllimport)");
143//
144// static_assert(true, "__declspec(dllimport)");
145//
146// When they're not working correctly, a syntax error should occur instead.
147#define EXPORT_TEMPLATE_TEST(want, export) \
148 static_assert(EXPORT_TEMPLATE_INVOKE( \
149 TEST_##want, EXPORT_TEMPLATE_STYLE(export, ), export), \
150 #export)
151#define EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(...) true
152#define EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK(...) true
153
154EXPORT_TEMPLATE_TEST(DEFAULT, );
155EXPORT_TEMPLATE_TEST(DEFAULT, __attribute__((visibility("default"))));
156EXPORT_TEMPLATE_TEST(MSVC_HACK, __declspec(dllexport));
157EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport));
158
159#undef EXPORT_TEMPLATE_TEST
160#undef EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT
161#undef EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK
162
163#endif // IPC_EXPORT_TEMPLATE_H_