[PATCH] D155713: [clang] Fix interaction between dllimport and exclude_from_explicit_instantiation

Hans Wennborg via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 16 05:50:12 PDT 2023


hans added a comment.

Apologies for the delay, I'm still catching up with my post-vacation backlog.

(For my notes, this came up in https://reviews.llvm.org/D153709)

I think the root of this bug is how class-level dll attributes get propagated to class members. Here is an example:

  template <typename T>
  struct __declspec(dllimport) S {
    void __attribute__((exclude_from_explicit_instantiation)) f() {}
  };
  
  extern template struct S<int>;

The problem is that when `S<int>` is explicitly instantiated, the dllimport attribute gets propagated to all its members, assuming all members are also being instantiated -- which may not be true now that `exclude_from_explicit_instantiation` exists.

I think the right location for the fix is where that inheritance happens:

  diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
  index a7ab0948d01b..12cb2542641a 100644
  --- a/clang/lib/Sema/SemaDeclCXX.cpp
  +++ b/clang/lib/Sema/SemaDeclCXX.cpp
  @@ -6592,6 +6592,13 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
       if (!VD && !MD)
         continue;
   
  +    if ((TSK == TSK_ExplicitInstantiationDeclaration ||
  +         TSK == TSK_ExplicitInstantiationDefinition) &&
  +        Member->hasAttr<ExcludeFromExplicitInstantiationAttr>()) {
  +      // Skip members excluded from instantiation.
  +      continue;
  +    }
  +
       if (MD) {
         // Don't process deleted methods.
         if (MD->isDeleted())

That's also the approach suggested in https://bugs.llvm.org/show_bug.cgi?id=41018#c0 (and it also handles the dllexport case.)

That doesn't handle the second of your test cases though, where dllimport is put on the member directly:

  template <typename T>
  struct  S {
    void __attribute__((exclude_from_explicit_instantiation)) __declspec(dllimport) f() {}
  };
  
  extern template struct S<int>;
  
  void use(S<int> &s) {
    s.f();
  }

Now, `S<int>::f` *is* technically being excluded from explicit instantiation as the attribute says, but when it gets implicitly instantiated it will be dllimport, because it was declared that way.

It's not clear to me how we'd want to handle that. I don't think it comes up in libc++, and I can't think of any code that would want to do that either, really.

https://bugs.llvm.org/show_bug.cgi?id=41018#c0 suggest emitting an error about incompatible attributes in that case. I suppose it could also be a warning, or we could do nothing for now.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155713/new/

https://reviews.llvm.org/D155713



More information about the cfe-commits mailing list