r327782 - [C++17] Allow an empty expression in an if init statement

Zhihao Yuan via cfe-commits cfe-commits at lists.llvm.org
Sat Mar 17 14:42:10 PDT 2018


Author: lichray
Date: Sat Mar 17 14:42:10 2018
New Revision: 327782

URL: http://llvm.org/viewvc/llvm-project?rev=327782&view=rev
Log:
[C++17] Allow an empty expression in an if init statement

Summary:
This fixes [PR35381](https://llvm.org/pr35381) and an additional bug where clang didn't warn about the C++17 extension when having an expression in the init statement.

Thanks Nicolas Lesser for contributing the patch.

Reviewers: rsmith

Reviewed By: rsmith

Subscribers: erik.pilkington, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D40445

Modified:
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/test/CXX/stmt.stmt/stmt.select/p3.cpp

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=327782&r1=327781&r2=327782&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Sat Mar 17 14:42:10 2018
@@ -1744,17 +1744,34 @@ Sema::ConditionResult Parser::ParseCXXCo
   ParsedAttributesWithRange attrs(AttrFactory);
   MaybeParseCXX11Attributes(attrs);
 
+  const auto WarnOnInit = [this, &CK] {
+    Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
+                                ? diag::warn_cxx14_compat_init_statement
+                                : diag::ext_init_statement)
+        << (CK == Sema::ConditionKind::Switch);
+  };
+
   // Determine what kind of thing we have.
   switch (isCXXConditionDeclarationOrInitStatement(InitStmt)) {
   case ConditionOrInitStatement::Expression: {
     ProhibitAttributes(attrs);
 
+    // We can have an empty expression here.
+    //   if (; true);
+    if (InitStmt && Tok.is(tok::semi)) {
+      WarnOnInit();
+      SourceLocation SemiLoc = ConsumeToken();
+      *InitStmt = Actions.ActOnNullStmt(SemiLoc);
+      return ParseCXXCondition(nullptr, Loc, CK);
+    }
+
     // Parse the expression.
     ExprResult Expr = ParseExpression(); // expression
     if (Expr.isInvalid())
       return Sema::ConditionError();
 
     if (InitStmt && Tok.is(tok::semi)) {
+      WarnOnInit();
       *InitStmt = Actions.ActOnExprStmt(Expr.get());
       ConsumeToken();
       return ParseCXXCondition(nullptr, Loc, CK);
@@ -1764,10 +1781,7 @@ Sema::ConditionResult Parser::ParseCXXCo
   }
 
   case ConditionOrInitStatement::InitStmtDecl: {
-    Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
-                                ? diag::warn_cxx14_compat_init_statement
-                                : diag::ext_init_statement)
-        << (CK == Sema::ConditionKind::Switch);
+    WarnOnInit();
     SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
     DeclGroupPtrTy DG =
         ParseSimpleDeclaration(DeclaratorContext::InitStmtContext, DeclEnd,

Modified: cfe/trunk/test/CXX/stmt.stmt/stmt.select/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/stmt.stmt/stmt.select/p3.cpp?rev=327782&r1=327781&r2=327782&view=diff
==============================================================================
--- cfe/trunk/test/CXX/stmt.stmt/stmt.select/p3.cpp (original)
+++ cfe/trunk/test/CXX/stmt.stmt/stmt.select/p3.cpp Sat Mar 17 14:42:10 2018
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z -Wc++14-compat -verify %s -DCPP17
 
 int f();
 
@@ -10,10 +11,67 @@ void g() {
   }
 }
 
-
 void h() {
   if (int x = f()) // expected-note 2{{previous definition}}
     int x; // expected-error{{redefinition of 'x'}}
   else
     int x; // expected-error{{redefinition of 'x'}}
 }
+
+void ifInitStatement() {
+  int Var = 0;
+
+  if (int I = 0; true) {}
+  if (Var + Var; true) {}
+  if (; true) {}
+#ifdef CPP17
+  // expected-warning at -4 {{if initialization statements are incompatible with C++ standards before C++17}}
+  // expected-warning at -4 {{if initialization statements are incompatible with C++ standards before C++17}}
+  // expected-warning at -4 {{if initialization statements are incompatible with C++ standards before C++17}}
+#else
+  // expected-warning at -8 {{'if' initialization statements are a C++17 extension}}
+  // expected-warning at -8 {{'if' initialization statements are a C++17 extension}}
+  // expected-warning at -8 {{'if' initialization statements are a C++17 extension}}
+#endif
+}
+
+void switchInitStatement() {
+  int Var = 0;
+
+  switch (int I = 0; Var) {}
+  switch (Var + Var; Var) {}
+  switch (; Var) {}
+#ifdef CPP17
+  // expected-warning at -4 {{switch initialization statements are incompatible with C++ standards before C++17}}
+  // expected-warning at -4 {{switch initialization statements are incompatible with C++ standards before C++17}}
+  // expected-warning at -4 {{switch initialization statements are incompatible with C++ standards before C++17}}
+#else
+  // expected-warning at -8 {{'switch' initialization statements are a C++17 extension}}
+  // expected-warning at -8 {{'switch' initialization statements are a C++17 extension}}
+  // expected-warning at -8 {{'switch' initialization statements are a C++17 extension}}
+#endif
+}
+
+// TODO: Better diagnostics for while init statements.
+void whileInitStatement() {
+  while (int I = 10; I--); // expected-error {{expected ')'}}
+  // expected-note at -1 {{to match this '('}}
+  // expected-error at -2 {{use of undeclared identifier 'I'}}
+
+  int Var = 10;
+  while (Var + Var; Var--) {} // expected-error {{expected ')'}}
+  // expected-note at -1 {{to match this '('}}
+  // expected-error at -2 {{expected ';' after expression}}
+  // expected-error at -3 {{expected expression}}
+  // expected-warning at -4 {{while loop has empty body}}
+  // expected-note at -5 {{put the semicolon on a separate line to silence this warning}}
+}
+
+// TODO: This is needed because clang can't seem to diagnose invalid syntax after the
+// last loop above. It would be nice to remove this.
+void whileInitStatement2() {
+  while (; false) {} // expected-error {{expected expression}}
+  // expected-warning at -1 {{expression result unused}}
+  // expected-error at -2 {{expected ';' after expression}}
+  // expected-error at -3 {{expected expression}}
+}




More information about the cfe-commits mailing list