如何在 clang 中使用 -std=c99 强制 Werror=declaration-after-statement
How to force Werror=declaration-after-statement with -std=c99 in clang
我希望编译器每次在语句后有声明时抛出错误,因为这是我想要强制执行的编码风格,但我也想用 -std=c99 编译,因为我使用了一些特定的 c99 功能。
问题是在 c99 中允许在代码中的任何地方声明,而不仅仅是在块的开头。
看看下面的程序:
// prog.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
int i = 0;
return 0;
}
如果我像这样用 gcc 编译这段代码:
gcc -std=c99 -Werror=declaration-after-statement prog.c
它抛出以下错误:
prog.c: In function ‘main’:
prog.c:6:9: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
6 | int i = 0;
| ^~~
cc1: some warnings being treated as errors
这是我希望在使用 clang 编译时的行为,但 clang 的行为不同。
如果我像这样用 clang 编译相同的代码:
clang -std=c99 -Werror=declaration-after-statement prog.c
它没有抛出任何错误。
只有当我用 clang 编译代码时,它才会抛出我想要的错误:
clang -std=c90 -Werror=declaration-after-statement prog.c
prog.c:6:6: error: ISO C90 forbids mixing declarations and code [-Werror,-Wdeclaration-after-statement]
int i = 0;
^
1 error generated.
但这对我不利,因为我需要使用 -std=c99
。
在使用 clang 编译时是否可以强制 -Werror=declaration-after-statement
和 -std=c99
一起编译?
看clang源码好像不支持
诊断在clang/include/clang/Basic/DiagnosticSemaKind.td
中定义
def ext_mixed_decls_code : Extension<
"ISO C90 forbids mixing declarations and code">,
InGroup<DiagGroup<"declaration-after-statement">>;
它的唯一用法是 clang/lib/Sema/SemaStmt.cpp
StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
// Note that __extension__ can be around a decl.
unsigned i = 0;
// Skip over all declarations.
for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
// We found the end of the list or a statement. Scan for another declstmt.
for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
if (i != NumElts) {
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
Diag(D->getLocation(), diag::ext_mixed_decls_code); // <-- here
}
}
...
注意 if
中的 !getLangOpts().C99
。诊断代码永远不会以高于 c90
.
的标准执行
好吧,你肯定可以尝试的一件事是自己构建 clang 并删除 if
的那部分,所以最终得到 if (!getLangOpts().CPlusPlus)
。
我试过了,它对我有用。
您可以使用 cmake -G "Ninja" -DCMAKE_BUILD_TYPE="Release" -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_C_COMPILER="/usr/bin/gcc" -DCMAKE_CXX_COMPILER="/usr/bin/g++" -DLLVM_PARALLEL_LINK_JOBS=2 -DLLVM_OPTIMIZED_TABLEGEN=ON path/to/llvm-project/llvm
配置 clang 构建
我希望编译器每次在语句后有声明时抛出错误,因为这是我想要强制执行的编码风格,但我也想用 -std=c99 编译,因为我使用了一些特定的 c99 功能。
问题是在 c99 中允许在代码中的任何地方声明,而不仅仅是在块的开头。
看看下面的程序:
// prog.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
int i = 0;
return 0;
}
如果我像这样用 gcc 编译这段代码:
gcc -std=c99 -Werror=declaration-after-statement prog.c
它抛出以下错误:
prog.c: In function ‘main’:
prog.c:6:9: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
6 | int i = 0;
| ^~~
cc1: some warnings being treated as errors
这是我希望在使用 clang 编译时的行为,但 clang 的行为不同。
如果我像这样用 clang 编译相同的代码:
clang -std=c99 -Werror=declaration-after-statement prog.c
它没有抛出任何错误。
只有当我用 clang 编译代码时,它才会抛出我想要的错误:
clang -std=c90 -Werror=declaration-after-statement prog.c
prog.c:6:6: error: ISO C90 forbids mixing declarations and code [-Werror,-Wdeclaration-after-statement]
int i = 0;
^
1 error generated.
但这对我不利,因为我需要使用 -std=c99
。
在使用 clang 编译时是否可以强制 -Werror=declaration-after-statement
和 -std=c99
一起编译?
看clang源码好像不支持
诊断在clang/include/clang/Basic/DiagnosticSemaKind.td
def ext_mixed_decls_code : Extension<
"ISO C90 forbids mixing declarations and code">,
InGroup<DiagGroup<"declaration-after-statement">>;
它的唯一用法是 clang/lib/Sema/SemaStmt.cpp
StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
// Note that __extension__ can be around a decl.
unsigned i = 0;
// Skip over all declarations.
for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
// We found the end of the list or a statement. Scan for another declstmt.
for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i)
/*empty*/;
if (i != NumElts) {
Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin();
Diag(D->getLocation(), diag::ext_mixed_decls_code); // <-- here
}
}
...
注意 if
中的 !getLangOpts().C99
。诊断代码永远不会以高于 c90
.
好吧,你肯定可以尝试的一件事是自己构建 clang 并删除 if
的那部分,所以最终得到 if (!getLangOpts().CPlusPlus)
。
我试过了,它对我有用。
您可以使用 cmake -G "Ninja" -DCMAKE_BUILD_TYPE="Release" -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_C_COMPILER="/usr/bin/gcc" -DCMAKE_CXX_COMPILER="/usr/bin/g++" -DLLVM_PARALLEL_LINK_JOBS=2 -DLLVM_OPTIMIZED_TABLEGEN=ON path/to/llvm-project/llvm