首页 > 解决方案 > 如何在 clang 中使用 -std=c99 强制 Werror=declaration-after-statement

问题描述

我想让编译器在每次声明后抛出一个错误,因为这是我想要强制执行的编码风格,但我也想使用 -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

标签: cgcccompiler-errorsclangc99

解决方案


查看 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
    }
  }
  ...

请注意!getLangOpts().C99. if诊断代码永远不会以上述标准执行c90

好吧,您肯定可以尝试的一件事是自己构建 clang 并删除if最终以if (!getLangOpts().CPlusPlus).

我试过了,它对我有用。

您可以使用以下命令配置 clang 构建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


推荐阅读