С помощью компилятора clang
вы можете увидеть их, передав аргумент -ast-dump
. Clang все еще находится в стадии разработки, но вы уже можете использовать его для следующих целей:
[js@HOST2 cpp]$ cat main1.cpp
struct A { };
[js@HOST2 cpp]$ clang++ -cc1 -ast-dump main1.cpp
typedef char *__builtin_va_list;
struct A {
public:
struct A;
inline A();
inline A(struct A const &);
inline struct A &operator=(struct A const &);
inline void ~A();
};
[js@HOST2 cpp]$
Надеюсь, ты об этом и просил. Давайте изменим код и посмотрим снова.
[js@HOST2 cpp]$ cat main1.cpp
struct M { M(M&); };
struct A { M m; };
[js@HOST2 cpp]$ clang++ -cc1 -ast-dump main1.cpp
typedef char *__builtin_va_list;
struct M {
public:
struct M;
M(struct M &);
inline struct M &operator=(struct M const &);
inline void ~M();
};
struct A {
public:
struct A;
struct M m;
inline A();
inline A(struct A &);
inline struct A &operator=(struct A const &);
inline void ~A();
};
[js@HOST2 cpp]$
Обратите внимание, что неявно объявленный конструктор копирования A
теперь имеет неконстантный ссылочный параметр, потому что у одного из его членов тоже есть (член m
), а у M
не объявлен конструктор по умолчанию.
Для получения сгенерированного кода вы можете разрешить ему использовать промежуточный язык виртуальной машины. Давайте посмотрим на сгенерированный код для этого:
struct A { virtual void f(); int a; };
A f() { A a; a = A(); return a; } // using def-ctor, assignment and copy-ctor
[js@HOST2 cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | c++filt
[ snippet ]
define linkonce_odr void @A::A()(%struct.A* nocapture %this) nounwind align 2 {
entry:
%0 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1]
store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %0
ret void
}
define linkonce_odr %struct.A* @A::operator=(A const&)(%struct.A* %this,
%struct.A* nocapture) nounwind align 2 {
entry:
%tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1]
%tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1]
%tmp3 = load i32* %tmp2 ; <i32> [#uses=1]
store i32 %tmp3, i32* %tmp
ret %struct.A* %this
}
define linkonce_odr void @A::A(A const&)(%struct.A* nocapture %this, %struct.A* nocapture)
nounwind align 2 {
entry:
%tmp = getelementptr inbounds %struct.A* %this, i32 0, i32 1 ; <i32*> [#uses=1]
%tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ; <i32*> [#uses=1]
%tmp3 = load i32* %tmp2 ; <i32> [#uses=1]
store i32 %tmp3, i32* %tmp
%1 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ; <i8***> [#uses=1]
store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %1
ret void
}
Теперь я не понимаю этот промежуточный язык (который определен в llvm.org ). Но вы можете перевести весь этот код в C, используя компилятор llvm:
[js@HOST2 cpp]$ clang++ -cc1 -O1 -emit-llvm -o - main1.cpp | llc -march=c -o - | c++filt
[snippet]
void A::A()(struct l_struct.A *llvm_cbe_this) {
*((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int )2u)]));
return;
}
struct l_struct.A *A::operator=(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A
*llvm_cbe_tmp__1) {
unsigned int llvm_cbe_tmp3;
llvm_cbe_tmp3 = *((&llvm_cbe_tmp__1->field1));
*((&llvm_cbe_this->field1)) = llvm_cbe_tmp3;
return llvm_cbe_this;
}
void A::A(A const&)(struct l_struct.A *llvm_cbe_this, struct l_struct.A *llvm_cbe_tmp__2) {
unsigned int llvm_cbe_tmp3;
llvm_cbe_tmp3 = *((&llvm_cbe_tmp__2->field1));
*((&llvm_cbe_this->field1)) = llvm_cbe_tmp3;
*((&llvm_cbe_this->field0)) = ((&_ZTV1A.array[((signed int )2u)]));
return;
}
Тад! Обратите внимание, как он устанавливает указатель виртуальной таблицы в конструкторе копирования и конструкторе по умолчанию. Надеюсь это поможет.