Why a function pointer field in a LLVM IR struct is replaced by {}*?

Dear LLVM developers,

My name is Ben Niu and I am a Ph.D. student at Lehigh University. I compiled the MUSL C library using Clang 3.3, and dumped the generated LLVM IR files. I found that the MUSL-defined FILE struct (aliasing __FILE_s)


struct __FILE_s {
    unsigned flags;
    unsigned char *rpos, *rend;
    int (*close)(FILE *);
    unsigned char *wend, *wpos;
    unsigned char *mustbezero_1;
    unsigned char *wbase;
    size_t (*read)(FILE *, unsigned char *, size_t);
    size_t (*write)(FILE *, const unsigned char *, size_t);
    off_t (*seek)(FILE *, off_t, int);
    unsigned char *buf;
    size_t buf_size;
    FILE *prev, *next;
    int fd;
    int pipe_pid;
    long lockcount;
    short dummy3;
    signed char mode;
    signed char lbf;
    int lock;
    int waiters;
    void *cookie;
    off_t off;
    char *getln_buf;
    void *mustbezero_2;
    unsigned char *shend;
    off_t shlim, shcnt;
};

was represented by


%struct.__FILE_s = type { i32, i8*, i8*, 
i32 (%struct.__FILE_s*)*, i8*, i8*, i8*, i8*, 
i64 (%struct.__FILE_s*, i8*, i64)*, 
i64 (%struct.__FILE_s*, i8*, i64)*, 
i64 (%struct.__FILE_s*, i64, i32)*, 
i8*, i64, %struct.__FILE_s*, %struct.__FILE_s*, 
i32, i32, i64, i16, i8, i8, i32, i32, i8*, 
i64, i8*, i8*, i8*, i64, i64 }

in some IR files, but was represented by


%struct.__FILE_s = type { i32, i8*, i8*, 
i32 (%struct.__FILE_s*)*, i8*, i8*, i8*, i8*, 
i64 (%struct.__FILE_s*, i8*, i64)*, 
{}*, 
i64 (%struct.__FILE_s*, i64, i32)*, 
i8*, i64, %struct.__FILE_s*, %struct.__FILE_s*, 
i32, i32, i64, i16, i8, i8, i32, i32, i8*, 
i64, i8*, i8*, i8*, i64, i64 }

in other source files. All these source files include the complete FILE struct definition. The only difference between these two IR structs is that a function pointer type field in the first form is replaced by {}* in the second form. Could anyone tell me why this happens and how to disable the {}* replacement?

clang/lib/CodeGen/CodeGenTypes.cpp; this behavior exists to protect the
type conversion code from infinite recursion. Our behavior could probably
be improved here; patches welcome (but be warned the code is rather
complicated).

Off the top of my head, I can't say why this is triggering in some files,
but not others.

-Eli

If the member is unused on that particular file, it might not have been
fully converted as it was unnecessary (or haven't triggered final
conversion).

cheers,
--renato