Skip to content

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

Open
@jslee02

Description

@jslee02

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().

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions