compiler-research / CppInterOp

A Clang-based C++ Interoperability Library
Other
38 stars 20 forks source link

Null access violation when using InstantiateTemplate with variadic class template #305

Open deadlocklogic opened 3 weeks ago

deadlocklogic commented 3 weeks ago

I am using the snippet: of the function static Decl* InstantiateTemplate(TemplateDecl* TemplateD, ArrayRef<TemplateArgument> TemplateArgs, Sema& S). It works unless the class template is variadic. Consider:

template <typename... T>
class ClassTemplate
{
};

Now when analyzing any instantiations of this template like for example: ClassTemplate<> I obtain an ClassTemplateSpecializationDecl CTSD with CTSD->getSpecializationKind() == clang::TemplateSpecializationKind::TSK_Undeclared. Now when trying to instantiate this class template with: InstantiateTemplate(CTSD->getSpecializedTemplate(), CTSD->getTemplateInstantiationArgs().asArray(), CI.getSema()); I get null access violation exception. Any ideas? Thanks.

vgvassilev commented 3 weeks ago

We have not added support for variadic templates yet. It was at some point in @maximusron's radar.

maximusron commented 3 weeks ago

@deadlocklogic I think we shouldn't be constructing the TemplateArgumentListInfo ourselves, can you try using this function : https://github.com/compiler-research/CppInterOp/blob/6a5f5649d2549337456391f672749213118a5b50/lib/Interpreter/CppInterOp.cpp#L2855-L2856 without using .asArray() for the args. If it doesn't work I was wondering if we should extract the clang::PackExpansionType and use the pattern, but looks like Sema::DeduceTemplateArguments does that already... @vgvassilev any idea what would be a good way to proceed here?

vgvassilev commented 3 weeks ago

I think we need to check what clang does in these cases and try to replay it in CppInterOp.

deadlocklogic commented 3 weeks ago

I solved my problem by unpacking template arguments when needed:

inline clang::Decl *InstantiateTemplate(clang::TemplateDecl *TemplateD,
                                        llvm::ArrayRef<clang::TemplateArgument> TemplateArgs, clang::Sema &S) {
  clang::TemplateArgumentListInfo TLI{};
  for (auto TA : TemplateArgs) {
    if (TA.getKind() == clang::TemplateArgument::ArgKind::Pack) {
      for (auto PTA : TA.getPackAsArray()) {
        TLI.addArgument(S.getTrivialTemplateArgumentLoc(PTA, clang::QualType(), clang::SourceLocation()));
      }
    } else {
      TLI.addArgument(S.getTrivialTemplateArgumentLoc(TA, clang::QualType(), clang::SourceLocation()));
    }
  }

  return InstantiateTemplate(TemplateD, TLI, S);
}

I don't know if there is a better solution.

vgvassilev commented 3 weeks ago

Can you submit a PR with tests for this change?

deadlocklogic commented 3 weeks ago

Ok, I can submit a PR fixing the issue. I will try writing a test too.