Home > Back-end >  How to force Werror=declaration-after-statement with -std=c99 in clang
How to force Werror=declaration-after-statement with -std=c99 in clang

Time:09-22

I would like to have compiler throw an error every time there is a declaration after statement because that is the coding style I want to enforce, but I also want to compile with -std=c99 since I use some of the specific c99 features.

The problem is that in c99 declarations are allowed anywhere in the code, not just at the beginning of a block.

Take a look at the following program:

// prog.c
#include <stdio.h>

int main(void)
{
    printf("hello world\n");
    int i = 0;

    return 0;
}

If I compile this code with gcc like this:

gcc -std=c99 -Werror=declaration-after-statement prog.c

it throws the following error:

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

This is the behavior I would like to have when compiling with clang, but clang behaves differently.

If I compile the same code with clang like this:

clang -std=c99 -Werror=declaration-after-statement prog.c

it throws no errors.

Only if I compile the code with clang like this it throws the error I want:

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.

But this is not good for me because I need to use -std=c99.

Is it possible to force -Werror=declaration-after-statement along with -std=c99 when compiling with clang?

CodePudding user response:

Looking at the source code of clang it seems like not supported.

The diagnostic is defined in clang/include/clang/Basic/DiagnosticSemaKind.td

def ext_mixed_decls_code : Extension<
  "ISO C90 forbids mixing declarations and code">,
  InGroup<DiagGroup<"declaration-after-statement">>;

And its only usage is in 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
    }
  }
  ...

Note the !getLangOpts().C99 in the if. The diagnose code will never execute with a standard above c90.

Well one thing you can surely try is build clang by yourself and delete that part of the if so end up with if (!getLangOpts().CPlusPlus).

I tried and it worked for me.

You can configure the clang build with 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

  • Related