view the default functions generated by a compiler?

后端 未结 5 1786
滥情空心
滥情空心 2020-12-28 22:17

Is there any way to view the default functions ( e.g., default copy constructor, default assignment operator ) generated by a compiler such as VC++2008 for a class which doe

5条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-28 22:56

    With the clang compiler, you can see them by passing the -ast-dump argument. Clang is still in development stage, but you can already use it for these things:

    [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]$
    

    I hope that's what you asked for. Let's change the code and look again.

    [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]$
    

    Notice how the implicitly declared copy constructor of A now has a non-const reference parameter, because one of its members has too (member m), and that M has no default constructor declared.

    For getting the generated code, you can let it emit virtual machine intermediate language. Let's look on the generated code for this:

    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 ;  [#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 ;  [#uses=1]
      %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ;  [#uses=1]
      %tmp3 = load i32* %tmp2                         ;  [#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 ;  [#uses=1]
      %tmp2 = getelementptr inbounds %struct.A* %0, i32 0, i32 1 ;  [#uses=1]
      %tmp3 = load i32* %tmp2                         ;  [#uses=1]
      store i32 %tmp3, i32* %tmp
      %1 = getelementptr inbounds %struct.A* %this, i32 0, i32 0 ;  [#uses=1]
      store i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2), i8*** %1
      ret void
    }
    

    Now, i don't understand that intermediate language (which is defined at llvm.org). But you can translate all that code into C using the llvm compiler:

    [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;
    }
    

    Tada! Notice how it sets the virtual table pointer in the copy constructor and default constructor. Hope this helps.

提交回复
热议问题