2013-04-19

LLVM/Clangがぜってーサポートしねーと宣言しているLinuxカーネルに多用されているGCC拡張

[Phoronix] LLVM/Clang 3.3 Should Be Close To Building Linux Kernel

LLVMLinux

Bug 9254 – clang can't build iptables in Linux kernel: error: fields must have a constant size: 'variable length array in structure' extension will never be supported

ClangでLinuxカーネルをビルドできる状況は、多くの勢力に望まれてきた。理由は様々だ。Clangはビルド時間が短い。静的解析による警告も優れている。ソースコードも綺麗だ。複数の独立した実装でコンパイルできるコードは、誤りを静的に発見しやすい移植性にも優れる。より優れたコピーレフトなライセンスであるGPLv3を嫌う哀しい勢力の存在もある。

現在のところ、ClangでLinuxカーネルをコンパイルするには、ClangとLinuxカーネル両方にパッチを当てなければならない。LLVM 3.3では、パッチはすべて正式に取り込まれ、LLVM側では素のままでLinuxカーネル側だけにパッチを当てればコンパイルできるようになるそうだ。

問題は、Linuxカーネルだ。LinuxカーネルはGCC拡張を多用しており、今のところClangでは動かない。LLVM側で実装すればいいGCC拡張もあるが、LLVMとしては実装したくない汚いGCC拡張もある。その最大の汚らしいGCC拡張が、構造体内でのvariable length arrayだ。

variable length array自体は、GCCは大昔から拡張機能としてサポートしている。C99では正式に採用された。

void f( size_t size )
{
    char a[size] ; // sizeは実行するまで分からない
}

配列の長さを実行時に指定できる機能だ。

ただし、C99でも採用していない、醜悪なGCC拡張がある。GCC拡張では、variable length arrayを構造体内で宣言できるのだ。これはその頭文字をとってVLAIS(Variable length arrays in structs)と呼ばれている。

void f( size_t size )
{
    struct
    {
        char a[size] ; // GCC拡張
    } s ;
}

VLAISはC99でも違法である。Clang側としては、VLAISをサポートする気は一切ない。Clangのエラーメッセージにもその意思がはっきりと現れている。

$ cat vlais.c
int main()
{
    int size = 1 ;
    struct
    {
        char a[size] ;
    } s ;
    return 0 ;
}
$ clang vlais.c
vlais.c:6:14: error: fields must have a constant size: 'variable length array in structure' extension will never be supported
        char a[size] ;
             ^
1 error generated.

そのため、LLVMでLinuxをビルドするプロジェクトであるLLVMLinuxでは、LinuxカーネルのVLAIS利用を書き換えるパッチを作成して、Linuxカーネルに採用してもらうよう働きかけているそうだ。

ところで、C99の規格に、VLAISを禁止する文面が見当たらないのだが、どのへんに書かれているのだろうか。ご存じの方は教えてお貰い申したい。

4 comments:

Takatoshi Kondo said...

s/配列内/構造体内/g
かな?

Takatoshi Kondo said...

このへんかなぁ。
6.7.2.1/8
A member of a structure or union may have any object type other than a variably
modified type.

6.7.5/3
A full declarator is a declarator that is not part of another declarator. The end of a full
declarator is a sequence point. If the nested sequence of declarators in a full declarator
contains a variable length array type, the type specified by the full declarator is said to be
variably modified.

y121516 said...

> ところで、C99の規格に、VLAISを禁止する文面が見当たらないのだが、どのへんに書かれているのだろうか。

通常の識別子(ordinary identifier)のVLAのみが許可されると書かれていますね。
VLAIS は通常の識別子ではないのでNG


6.7.5.2 Array declarators

2 Only an ordinary identifier (as defined in 6.2.3) with both block scope or function
prototype scope and no linkage shall have a variably modified type.

で、10 EXAMPLE 4 に not ordinary identifier として、構造体のメンバの例が載っています。


ordinary identifier は(抜粋なので不完全ですが)次のように定義されています。
6.2.3 Name spaces of identifiers
— the members of structures or unions; each structure or union has a separate name
space for its members (disambiguated by the type of the expression used to access the
member via the . or -> operator);
— all other identifiers, called ordinary identifiers (declared in ordinary declarators or as
enumeration constants).

江添亮 said...

なるほど。どうも。