Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -693,6 +693,7 @@ def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">; def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">; def Fallback : DiagGroup<"fallback">; +def MisleadingIndentation : DiagGroup<"misleading-indentation">; // This covers both the deprecated case (in C++98) // and the extension case (in C++11 onwards). @@ -861,7 +862,8 @@ PrivateExtern, SelTypeCast, ExternCCompat, - UserDefinedWarnings + UserDefinedWarnings, + MisleadingIndentation ]>; // Thread Safety warnings Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -61,6 +61,12 @@ "remove unnecessary ';' to silence this warning">, InGroup, DefaultIgnore; +def warn_misleading_indentation : Warning< + "this indention is missleading; this statement is not part of the previous" + " '%0'">, InGroup, DefaultIgnore; +def note_previous_statement : Note< + "previous statement is here">; + def ext_thread_before : Extension<"'__thread' before '%0'">; def ext_keyword_as_ident : ExtWarn< "keyword '%0' will be made available as an identifier " Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -1191,6 +1191,19 @@ return false; } +static void MaybeDiagnoseMisleadingIndentation(Parser &P, Token Tok, + SourceLocation PrevLoc, + SourceLocation StmtLoc, + const char *StmtName) { + SourceManager& SM = P.getPreprocessor().getSourceManager(); + unsigned PrevStmtColNum = SM.getSpellingColumnNumber(PrevLoc); + unsigned CurStmtColNum = SM.getSpellingColumnNumber(Tok.getLocation()); + if (PrevStmtColNum != 0 && CurStmtColNum != 0 && + PrevStmtColNum <= CurStmtColNum) { + P.Diag(Tok.getLocation(), diag::warn_misleading_indentation) << StmtName; + P.Diag(StmtLoc, diag::note_previous_statement); + } +} /// ParseIfStatement /// if-statement: [C99 6.8.4.1] @@ -1281,6 +1294,9 @@ // Pop the 'if' scope if needed. InnerScope.Exit(); + if (Tok.isNot(tok::kw_else)) + MaybeDiagnoseMisleadingIndentation(*this, Tok, ThenStmtLoc, IfLoc, "if"); + // If it has an else, parse it. SourceLocation ElseLoc; SourceLocation ElseStmtLoc; @@ -1313,6 +1329,9 @@ // Pop the 'else' scope if needed. InnerScope.Exit(); + if (ElseStmt.isUsable()) + MaybeDiagnoseMisleadingIndentation( + *this, Tok, ElseStmt.get()->getBeginLoc(), ElseLoc, "else"); } else if (Tok.is(tok::code_completion)) { Actions.CodeCompleteAfterIf(getCurScope()); cutOffParsing(); @@ -1491,6 +1510,10 @@ InnerScope.Exit(); WhileScope.Exit(); + if (Body.isUsable()) + MaybeDiagnoseMisleadingIndentation(*this, Tok, Body.get()->getBeginLoc(), + WhileLoc, "while"); + if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); @@ -1927,6 +1950,10 @@ // Leave the for-scope. ForScope.Exit(); + if (Body.isUsable()) + MaybeDiagnoseMisleadingIndentation(*this, Tok, Body.get()->getBeginLoc(), + ForLoc, "for"); + if (Body.isInvalid()) return StmtError(); Index: clang/test/SemaCXX/warn-misleanding-indentation.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/warn-misleanding-indentation.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wmisleading-indentation -DWITH_WARN %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -DWITH_WARN %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wall -Wno-misleading-indentation %s + +#ifndef WITH_WARN +// expected-no-diagnostics +#endif + +void f0(int i) { + if (i) +#ifdef WITH_WARN +// expected-note@-2 {{here}} +#endif + i = i + 1; + i *= 2; +#ifdef WITH_WARN +// expected-warning@-2 {{indention is missleading}} +#endif + return; +} + +void f1(int i) { + for (;i;) +#ifdef WITH_WARN +// expected-note@-2 {{here}} +#endif + i = i + 1; + i *= 2; +#ifdef WITH_WARN +// expected-warning@-2 {{indention is missleading}} +#endif + return; +} + +void f2(int i) { + while (i) +#ifdef WITH_WARN +// expected-note@-2 {{here}} +#endif + i = i + 1; i *= 2; +#ifdef WITH_WARN +// expected-warning@-2 {{indention is missleading}} +#endif + return; +} + +void f3(int i) { + if (i) + i = i + 1; + else +#ifdef WITH_WARN +// expected-note@-2 {{here}} +#endif + i *= 2; + return; +#ifdef WITH_WARN +// expected-warning@-2 {{indention is missleading}} +#endif +}