Obtenha constexpr sem executar o programa

Dec 04 2020

Eu tenho uma biblioteca (como fonte e compilada) e estou escrevendo um programa (não vinculado a esta biblioteca) que precisa saber se algum tipo na biblioteca, por exemplo, pode ser copiado facilmente ou não.

Eu poderia fazer meu programa escrever o seguinte em 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';
}

em seguida, compile e execute esse código e analise a saída. Existe uma maneira melhor de obter essas informações? (o desempenho é importante). A libclang pode fazer isso?

ATUALIZAR devido a comentários:

Com relação ao problema XY: O que estou tentando fazer é escrever um programa (chamado rust-bindgen) em rust, que obtém o caminho de um arquivo de cabeçalho C ++ como um argumento e gera ligações rust-c ++ para esse arquivo de cabeçalho. Preciso gerar as ligações de maneira diferente, dependendo se o tipo é trivialmente copiável / relocável.

Portanto, tenho um caminho para um arquivo de cabeçalho C ++ e preciso saber se um determinado tipo definido nesse arquivo de cabeçalho pode ser copiado de maneira trivial. A abordagem acima funciona, mas é lenta, porque envolve a compilação de file.cpp.

TLDR: Como posso escrever uma função de ferrugem rápida, que recebe duas strings como argumento e retorna um bool: A primeira string é o caminho para um arquivo de cabeçalho C ++, a segunda string é o nome de um tipo definido no referido arquivo de cabeçalho. Ele deve retornar um bool que diz se o tipo é trivialmente copiável ou não.

Respostas

2 ecatmur Dec 04 2020 at 04:56

Você vai precisar compilar o código, pelo menos para IR. Isso ocorre porque a trivialidade de uma classe C ++ pode depender de uma computação arbitrariamente complicada cujas entradas podem incluir atributos de plataforma, cabeçalhos disponíveis, definições de pré-processador, opções de compilador etc., que, portanto, só podem ser realizadas por um compilador C ++.

Se você estiver chamando o clang como um binário, a opção de emitir IR é clang -S -emit-llvme você desejará analisar a saída IR do LLVM; por exemplo para

#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;

o IR é:

@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

Se você quiser usar libclang, você precisará invocar EmitLLVMOnlyAction fornecendo um Módulo do qual você pode extrair as definições GlobalVariable. Veja: Método para criar LLVM IR