foo
Clangがin functionへのすべての参照を単純に削除する場合、警告はペダンディックレベルでのみ発生するため、バグではないにしても、少なくとも不公平だと思いますnocall
。これは、アセンブリ コードをデバッグ モード ( c++ -S -g file.cpp
) で見て、コンパイラが各行をどのように解釈するかを正確に確認することで確認できます。
.s で生成されたファイルを見ると、呼び出しで 20 行目Foo foo = {...
と 25行目printInfo(foo)
が生成されていることがわかります。
.loc 1 20 0 # ess.cpp:20:0
movq %rcx, -64(%rbp)
movq -40(%rbp), %rcx
.Ltmp45:
movq %rcx, -56(%rbp)
.loc 1 24 0 # ess.cpp:24:0
movq %rax, %rdi
callq _ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc
leaq -64(%rbp), %rdi
leaq _ZNSt3__14endlIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_, %rcx
movq %rax, -24(%rbp)
movq %rcx, -32(%rbp)
movq -24(%rbp), %rax
.loc 5 322 0 # /usr/include/c++/v1/ostream:322:0
.Ltmp46:
movq %rdi, -72(%rbp) # 8-byte Spill
movq %rax, %rdi
callq *-32(%rbp)
.Ltmp47:
.loc 1 25 0 # ess.cpp:25:0
movq -72(%rbp), %rdi # 8-byte Reload
movq %rax, -80(%rbp) # 8-byte Spill
callq _Z9printInfoRK3Foo
leaq _ZNSt3__14coutE, %rdi
leaq .L.str2, %rsi
ただし、nocall の場合、対応する行 (30 と 35) は次のようにはなりません。
.loc 1 29 0 prologue_end # ess.cpp:29:0
.Ltmp57:
movl .L_ZZ6noCallR3BuuE3acc, %ecx
movl %ecx, -48(%rbp)
.loc 1 34 0 # ess.cpp:34:0
movq %rax, %rdi
callq _ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc
leaq _ZNSt3__14coutE, %rdi
leaq .L.str2, %rsi
leaq _ZNSt3__14endlIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_, %rdx
movq %rax, -24(%rbp)
movq %rdx, -32(%rbp)
movq -24(%rbp), %rax
.loc 5 322 0 # /usr/include/c++/v1/ostream:322:0
.Ltmp58:
movq %rdi, -72(%rbp) # 8-byte Spill
movq %rax, %rdi
movq %rsi, -80(%rbp) # 8-byte Spill
callq *-32(%rbp)
.Ltmp59:
.loc 1 36 0 # ess.cpp:36:0
movq -72(%rbp), %rdi # 8-byte Reload
movq -80(%rbp), %rsi # 8-byte Reload
movq %rax, -88(%rbp) # 8-byte Spill
callq _ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc
leaq _ZNSt3__14endlIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_, %rdx
movq %rax, -8(%rbp)
movq %rdx, -16(%rbp)
movq -8(%rbp), %rdi
.loc 5 322 0 # /usr/include/c++/v1/ostream:322:0
.Ltmp60:
callq *-16(%rbp)
.Ltmp61:
.loc 1 37 0 # ess.cpp:37:0
cpp ファイルの番号付きの行は次のとおりです。
18 void call( Buu& buu ) {
19 Acc acc = { 1 };
20 Foo foo = {
21 .acc = acc,
22 .buu = buu,
23 };
24 std::cout << "before" << std::endl;
25 printInfo( foo );
26 std::cout << "after" << std::endl;
27 }
28 void noCall( Buu& buu ) {
29 Acc acc = { 1 };
30 Foo foo = {
31 .buu = buu,
32 .acc = acc
33 };
34 std::cout << "before" << std::endl;
35 printInfo( foo );
36 std::cout << "after" << std::endl;
37 }
私の理解では、clang は、C++ モードで C99 構文を処理しない場合でも、C99 構文を処理するふりをします。
私見、これは clang に報告できるバグです。少なくとも 1.4 実装コンプライアンス [intro.compliance] に従って診断を発行する必要があるためです。
1診断可能な規則のセットは、「診断は必要ない」という明示的な表記を含む規則、または「未定義の動作」をもたらすと記述されている規則を除いて
、この国際規格のすべての構文規則および意味規則で構成されます。
2 この国際標準は C++ 実装に関する要件のみを述べていますが、これらの要件は、プログラム、プログラムの一部、またはプログラムの実行に関する要件として表現されている場合、理解しやすいことがよくあります。このような要件には、次の意味があります。
- プログラムにこの国際規格の規則違反が含まれていない場合、適合する実装は、そのリソース制限内で、そのプログラムを受け入れて正しく実行する必要があります。
- 実装がその構成をサポートしていないのに、プログラムが診断可能な規則の違反、またはこの標準で「条件付きでサポートされる」と記述されている構成の発生を
含む場合、適合する実装は少なくとも 1 つの診断メッセージを発行するものとします。
...
8 準拠する実装には、整形式プログラムの動作を変更しないという条件で、拡張 (追加のライブラリ関数を含む) を含めることができます。実装は、この国際標準に従って不適切な形式の拡張機能を使用するプログラムを診断する必要があります。ただし、そうした後は、そのようなプログラムをコンパイルして実行できます。