Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not generating fully qualified type name for non-type template argument #335

Open
jslee02 opened this issue May 6, 2020 · 0 comments
Open

Comments

@jslee02
Copy link
Member

jslee02 commented May 6, 2020

Current Behavior

// C++ source
namespace chimera_test { namespace common {
constexpr int Dynamic = -1;
} }

namespace chimera_test { namespace math {
template <int Dimension>
class Vector {
public:
    Vector() = default;
};
using VectorX = Vector<common::Dynamic>;
} }
// Binding code
void _ZN12chimera_test4math6VectorILin1EEE(::pybind11::module& m) {
    auto sm = m.def_submodule("math");
    auto attr = sm;
    ::pybind11::class_<chimera_test::math::Vector<common::Dynamic> >(attr, "VectorX")  // 'common::Dynamic' is expected to be 'chimera_test::common::Dynamic'
        .def(::pybind11::init<>());
}

The template argument of Vector, Dynamic, is not fully qualified.

  • Expected: chimera_test::math::Vector<chimera_test::common::Dynamic> or chimera_test::math::Vector<-1> (after evaluated)
  • Actual: chimera_test::math::Vector<common::Dynamic>

Reasoning

Type template arguments are converted to fully qualified type name here:

static bool
GetFullyQualifiedTemplateArgument(const ASTContext& Ctx,
TemplateArgument &arg) {
bool changed = false;
// Note: we do not handle TemplateArgument::Expression, to replace it
// we need the information for the template instance decl.
// See GetPartiallyDesugaredTypeImpl
if (arg.getKind() == TemplateArgument::Template) {
TemplateName tname = arg.getAsTemplate();
changed = GetFullyQualifiedTemplateName(Ctx, tname);
if (changed) {
arg = TemplateArgument(tname);
}
} else if (arg.getKind() == TemplateArgument::Type) {
QualType SubTy = arg.getAsType();
// Check if the type needs more desugaring and recurse.
QualType QTFQ = TypeName::GetFullyQualifiedType(SubTy, Ctx);
if (QTFQ != SubTy) {
arg = TemplateArgument(QTFQ);
changed = true;
}
} else if (arg.getKind() == TemplateArgument::Pack) {
SmallVector<TemplateArgument, 2> desArgs;
for (auto I = arg.pack_begin(), E = arg.pack_end(); I != E; ++I) {
TemplateArgument pack_arg(*I);
changed = GetFullyQualifiedTemplateArgument(Ctx,pack_arg);
desArgs.push_back(pack_arg);
}
if (changed) {
// The allocator in ASTContext is mutable ...
// Keep the argument const to be inline will all the other interfaces
// like: NestedNameSpecifier::Create
ASTContext &mutableCtx( const_cast<ASTContext&>(Ctx) );
arg = TemplateArgument::CreatePackCopy(mutableCtx, ARRAY_COMPAT(desArgs));
}
}
return changed;
}

However, non-type template arguments not handled by this function, as documented in the code (line: 266-268).

Simple Workaround

For this particular case, we can work around by putting using namespace chimera_test; to the configuration YAML in the template section accordingly. But I'm not sure if this could be problematic in other situations.

Possible Approaches

Overwriting Type of Expression

We could print the expression by:

Expr* expr = arg.getAsExpr();
llvm::SmallString<256> Buf;
llvm::raw_svector_ostream StrOS(Buf);
PrintingPolicy Policy(Ctx.getPrintingPolicy());
Policy.SuppressScope = false;
Policy.AnonymousTagLocations = false;
expr->printPretty(StrOS, nullptr, Policy);
std::string str = StrOS.str();  // common::Dynamic

Once we get the expression in string, we might be able to get the fully qualified type by using chimera::util::resolveType() and cling::utils::GetFullyQualifiedType(). Then we could overwrite the type by expr->setType(fully_qualified_type).

This approach requires to change the code dependencies so that we can call chimera::util::resolveType() in cling_utils_AST.cpp. I haven't tested this approach yet for this limitation.

Overwriting Output of Fully-Qualified Type Name

This would be a more hacky version than the previous one. We could modify cling::utils::GetFullyQualifiedType() to return which template arguments are still needed to be fully-qualified, and update them afterward. This is because we don't have control over clang::QualType::getAsString().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant