Volker Weißmann
Volker Weißmann

Reputation: 574

Get constexpr without running the program

I have a library (both as source and compiled) and I'm writing a program (not linked to this library) that needs to know if some type in the library is e.g. trivially copyable or not.

I could make my program write the following into file.cpp:

#include "mylibrary.hpp"
int main()
{
    std::cout << std::is_trivially_copyable<A>::value << '\n';
    std::cout << std::is_trivially_copyable<B>::value << '\n';
    std::cout << std::is_trivially_copyable<C>::value << '\n';
    std::cout << std::is_trivially_copyable<D>::value << '\n';
}

then compile and run this code and parse the output. Is there a better way to get this information? (performance is important). Can libclang do that?

UPDATE because of comments:

Regarding the XY problem: What I'm trying to do, is write a program (called rust-bindgen) in rust, that gets the path of a C++ header file as am argument and generates rust-c++ bindings for that header file. I need to generating the bindings differently depending on whether the type is trivially copyable/relocatable.

So I have a path to a C++ header file and I need to know whether a given type that is defined in that header file is trivially copyable. The approach above works, but is slow, because it involves compiling file.cpp.

TLDR: How can I write a fast rust function, that takes two strings as an argument and returns a bool: The first string is the path to a C++ header file, the second string is the name of a type defined in said header file. It should return a bool that says whether the type is trivially copyable or not.

Upvotes: 1

Views: 110

Answers (1)

ecatmur
ecatmur

Reputation: 157374

You are going to need to compile the code, at least to IR. This is because the triviality of a C++ class can depend on an arbitrarily complicated computation whose inputs may include platform attributes, available headers, preprocessor defines, compiler options etc., which can thus only be carried out by a C++ compiler.

If you are invoking clang as a binary the option to emit IR is clang -S -emit-llvm and you will then want to parse the LLVM IR output; for example for

#include <type_traits>
struct A {};
struct B { B(B const&); };
struct C { ~C(); };
struct D { D(D const&) = default; };
int a = std::is_trivially_copyable<A>::value;
int b = std::is_trivially_copyable<B>::value;
int c = std::is_trivially_copyable<C>::value;
int d = std::is_trivially_copyable<D>::value;

the IR is:

@a = dso_local local_unnamed_addr global i32 1, align 4, !dbg !0
@b = dso_local local_unnamed_addr global i32 0, align 4, !dbg !6
@c = dso_local local_unnamed_addr global i32 0, align 4, !dbg !10
@d = dso_local local_unnamed_addr global i32 1, align 4, !dbg !12
 ^ variable name                             ^ initializer

If you want to use libclang, you will need to invoke EmitLLVMOnlyAction giving a Module which you can then extract the GlobalVariable definitions from. See: Method to create LLVM IR

Upvotes: 2

Related Questions