@@ -241,12 +241,19 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
241
241
return false ;
242
242
}
243
243
244
- public:
245
- visitor (clang::ASTContext &context, PPCallbacks::FileIncludes &file_includes)
246
- : context_(context), source_manager_(context.getSourceManager()),
247
- file_includes_ (file_includes) {}
244
+ // Determine if a tagged type needs exporting at the record level.
245
+ // Returns true if the record has been, or was already, annotated. Returns
246
+ // false otherwise.
247
+ bool export_record_if_needed (clang::CXXRecordDecl *RD) {
248
+ // Check if the class is already exported.
249
+ if (is_symbol_exported (RD))
250
+ return true ;
251
+
252
+ // Skip exporting template classes. For fully-specialized template classes,
253
+ // isTemplated() returns false so they will be annotated if needed.
254
+ if (RD->isTemplated ())
255
+ return false ;
248
256
249
- bool TraverseCXXRecordDecl (clang::CXXRecordDecl *RD) {
250
257
// If a class declaration contains an out-of-line virtual method, annotate
251
258
// the class instead of its individual members. This ensures its vtable is
252
259
// exported on non-Windows platforms. Do this regardless of the method's
@@ -258,22 +265,31 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
258
265
(MD->isVirtual () && !MD->hasBody ())))
259
266
break ;
260
267
261
- const bool is_exported_record = is_symbol_exported (RD);
262
- if (!is_exported_record && should_export_record) {
263
- // Insert the annotation immediately before the tag name, which is the
264
- // position returned by getLocation.
265
- clang::LangOptions LO = RD-> getASTContext (). getLangOpts ();
266
- clang::SourceLocation SLoc = RD->getLocation ();
267
- const clang::SourceLocation location =
268
- context_. getFullLoc (SLoc). getExpansionLoc ();
269
- unexported_public_interface (location)
270
- << RD << clang::FixItHint::CreateInsertion (SLoc, export_macro + " " );
271
- }
268
+ if (!should_export_record)
269
+ return false ;
270
+
271
+ // Insert the annotation immediately before the tag name, which is the
272
+ // position returned by getLocation.
273
+ clang::LangOptions LO = RD->getASTContext (). getLangOpts ();
274
+ clang::SourceLocation SLoc = RD-> getLocation ();
275
+ const clang::SourceLocation location =
276
+ context_. getFullLoc (SLoc). getExpansionLoc ();
277
+ unexported_public_interface (location)
278
+ << RD << clang::FixItHint::CreateInsertion (SLoc, export_macro + " " );
272
279
280
+ return true ;
281
+ }
282
+
283
+ public:
284
+ visitor (clang::ASTContext &context, PPCallbacks::FileIncludes &file_includes)
285
+ : context_(context), source_manager_(context.getSourceManager()),
286
+ file_includes_ (file_includes) {}
287
+
288
+ bool TraverseCXXRecordDecl (clang::CXXRecordDecl *RD) {
273
289
// Save/restore the current value of in_exported_record_ to support nested
274
290
// record definitions.
275
291
const bool old_in_exported_record = in_exported_record_;
276
- in_exported_record_ = is_exported_record || should_export_record ;
292
+ in_exported_record_ = export_record_if_needed (RD) ;
277
293
278
294
// Traverse the class by invoking the parent's version of this method. This
279
295
// call is required even if the record is exported because it may contain
@@ -283,6 +299,30 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
283
299
return result;
284
300
}
285
301
302
+ // RecursiveASTVisitor::TraverseCXXRecordDecl does not get called for fully
303
+ // specialized template declarations. Since we may want to export them,
304
+ // manually invoke TraverseCXXRecordDecl whenever an explicit specialization
305
+ // is found.
306
+ bool TraverseClassTemplateSpecializationDecl (
307
+ clang::ClassTemplateSpecializationDecl *SD) {
308
+ switch (SD->getSpecializationKind ()) {
309
+ case clang::TSK_ExplicitSpecialization:
310
+ // This call visits class template specialization record and recursively
311
+ // visits all of it children, which may also require export.
312
+ return TraverseCXXRecordDecl (SD);
313
+
314
+ // TODO: consider annotating explicit template instantiation declarations
315
+ // and definitions in the future. They may require unique annotation macros
316
+ // due to differences between visibility and dllexport/dllimport attributes.
317
+ case clang::TSK_ExplicitInstantiationDeclaration:
318
+ [[fallthrough]];
319
+ case clang::TSK_ExplicitInstantiationDefinition:
320
+ [[fallthrough]];
321
+ default :
322
+ return true ;
323
+ }
324
+ }
325
+
286
326
bool VisitFunctionDecl (clang::FunctionDecl *FD) {
287
327
clang::FullSourceLoc location = get_location (FD);
288
328
0 commit comments