public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: C++ PATCH for C++17 selection statements with initializer
@ 2016-11-06  2:03 David Edelsohn
  2016-11-16  1:02 ` Marek Polacek
  0 siblings, 1 reply; 10+ messages in thread
From: David Edelsohn @ 2016-11-06  2:03 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill

The patch adds testcase init-statement6.C, which includes the declaration

extern void publish (int), raise (int);

POSIX defines

int raise (int);

in <signal.h> which gets included by the C++ headers for the testcase on AIX.

This is causes the error message:

/nasfarm/edelsohn/src/src/gcc/testsuite/g++.dg/cpp1z/init-statement6.C:10:28:
error: ambiguating new declaration of 'void raise(int)'
...
/tmp/GCC/gcc/include-fixed/sys/signal.h:103:12: note: old declaration
'int raise(int)'

Is there a reason for the conflicting / ambiguating declaration?

Thanks, David

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: C++ PATCH for C++17 selection statements with initializer
  2016-11-06  2:03 C++ PATCH for C++17 selection statements with initializer David Edelsohn
@ 2016-11-16  1:02 ` Marek Polacek
  0 siblings, 0 replies; 10+ messages in thread
From: Marek Polacek @ 2016-11-16  1:02 UTC (permalink / raw)
  To: David Edelsohn; +Cc: GCC Patches, Jason Merrill

On Sat, Nov 05, 2016 at 10:03:37PM -0400, David Edelsohn wrote:
> The patch adds testcase init-statement6.C, which includes the declaration
> 
> extern void publish (int), raise (int);
> 
> POSIX defines
> 
> int raise (int);
> 
> in <signal.h> which gets included by the C++ headers for the testcase on AIX.
> 
> This is causes the error message:
> 
> /nasfarm/edelsohn/src/src/gcc/testsuite/g++.dg/cpp1z/init-statement6.C:10:28:
> error: ambiguating new declaration of 'void raise(int)'
> ...
> /tmp/GCC/gcc/include-fixed/sys/signal.h:103:12: note: old declaration
> 'int raise(int)'
> 
> Is there a reason for the conflicting / ambiguating declaration?

Oops, no reason at all.  I'm fixing this with:

Tested on x86_64-linux, applying to trunk.

2016-11-15  Marek Polacek  <polacek@redhat.com>

	* g++.dg/cpp1z/init-statement6.C: Rename a function.

diff --git gcc/testsuite/g++.dg/cpp1z/init-statement6.C gcc/testsuite/g++.dg/cpp1z/init-statement6.C
index 53b0d31..e8e24b5 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement6.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement6.C
@@ -7,14 +7,14 @@
 
 std::map<int, std::string> m;
 extern int xread (int *);
-extern void publish (int), raise (int);
+extern void publish (int), xraise (int);
 
 void
 foo ()
 {
   if (auto it = m.find (10); it != m.end ()) { std::string s = it->second; }
   if (char buf[10]; std::fgets(buf, 10, stdin)) { m[0] += buf; }
-  if (int s; int count = xread (&s)) { publish(count); raise(s); }
+  if (int s; int count = xread (&s)) { publish(count); xraise(s); }
 
   const char *s;
   if (auto keywords = {"if", "for", "while"};

	Marek

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: C++ PATCH for C++17 selection statements with initializer
  2016-10-05 17:10       ` Marek Polacek
@ 2016-10-05 17:32         ` Jason Merrill
  0 siblings, 0 replies; 10+ messages in thread
From: Jason Merrill @ 2016-10-05 17:32 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

OK.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: C++ PATCH for C++17 selection statements with initializer
  2016-10-05 16:12     ` Jason Merrill
@ 2016-10-05 17:10       ` Marek Polacek
  2016-10-05 17:32         ` Jason Merrill
  0 siblings, 1 reply; 10+ messages in thread
From: Marek Polacek @ 2016-10-05 17:10 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Wed, Oct 05, 2016 at 12:11:40PM -0400, Jason Merrill wrote:
> On Wed, Oct 5, 2016 at 11:29 AM, Marek Polacek <polacek@redhat.com> wrote:
> > How about the version I just posted, i.e.
> > <https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00252.html>?
> 
> That doesn't address my first comment.

The following uses cp_parser_skip_to_closing_parenthesis_1, and is, I think,
much nicer.

Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk?

2016-10-05  Marek Polacek  <polacek@redhat.com>

	Implement P0305R1, Selection statements with initializer.
	* cp-array-notation.c (create_an_loop): Call finish_init_stmt
	instead of finish_for_init_stmt.
	* cp-tree.h (finish_for_init_stmt): Rename to finish_init_stmt.
	* decl.c (poplevel): Adjust a comment.
	* init.c (build_vec_init): Call finish_init_stmt instead of
	finish_for_init_stmt.
	* name-lookup.c (pushdecl_maybe_friend_1): Adjust a comment.
	* name-lookup.h (enum scope_kind): Likewise.
	* parser.c (cp_parser_statement): Update commentary.
	(cp_parser_init_statement_p): New function.
	(cp_parser_selection_statement): Parse the optional init-statement.
	(cp_parser_for): Call finish_init_stmt instead of finish_for_init_stmt.
	(cp_parser_c_for): Likewise.
	(cp_convert_range_for): Call finish_init_stmt instead of finish_for_init_stmt.
	(cp_parser_range_for_member_function): Update commentary.
	(cp_parser_iteration_statement):
	(cp_parser_for_init_statement): Rename to cp_parser_init_statement.
	* pt.c (tsubst_omp_for_iterator): Update commentary.
	(tsubst_expr): Call finish_init_stmt instead of finish_for_init_stmt.
	* semantics.c (finish_for_init_stmt): Rename to finish_init_stmt.
	Update commentary.

	* g++.dg/cpp1z/init-statement1.C: New test.
	* g++.dg/cpp1z/init-statement2.C: New test.
	* g++.dg/cpp1z/init-statement3.C: New test.
	* g++.dg/cpp1z/init-statement4.C: New test.
	* g++.dg/cpp1z/init-statement5.C: New test.
	* g++.dg/cpp1z/init-statement6.C: New test.
	* g++.dg/cpp1z/init-statement7.C: New test.
	* g++.dg/cpp1z/init-statement8.C: New test.

diff --git gcc/cp/cp-array-notation.c gcc/cp/cp-array-notation.c
index 4687ced..633ab09 100644
--- gcc/cp/cp-array-notation.c
+++ gcc/cp/cp-array-notation.c
@@ -66,7 +66,7 @@ create_an_loop (tree init, tree cond, tree incr, tree body)
 
   finish_expr_stmt (init);
   for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
-  finish_for_init_stmt (for_stmt);
+  finish_init_stmt (for_stmt);
   finish_for_cond (cond, for_stmt, false);
   finish_for_expr (incr, for_stmt);
   finish_expr_stmt (body);
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 3fbe1d9..92e4017 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -6297,7 +6297,7 @@ extern void finish_do_stmt			(tree, tree, bool);
 extern tree finish_return_stmt			(tree);
 extern tree begin_for_scope			(tree *);
 extern tree begin_for_stmt			(tree, tree);
-extern void finish_for_init_stmt		(tree);
+extern void finish_init_stmt			(tree);
 extern void finish_for_cond			(tree, tree, bool);
 extern void finish_for_expr			(tree, tree);
 extern void finish_for_stmt			(tree);
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 6646062..6a08d8f 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -639,9 +639,8 @@ poplevel (int keep, int reverse, int functionbody)
       BLOCK_SUPERCONTEXT (link) = block;
 
   /* We still support the old for-scope rules, whereby the variables
-     in a for-init statement were in scope after the for-statement
-     ended.  We only use the new rules if flag_new_for_scope is
-     nonzero.  */
+     in a init statement were in scope after the for-statement ended.
+     We only use the new rules if flag_new_for_scope is nonzero.  */
   leaving_for_scope
     = current_binding_level->kind == sk_for && flag_new_for_scope == 1;
 
diff --git gcc/cp/init.c gcc/cp/init.c
index 2d5877d..d1c8274 100644
--- gcc/cp/init.c
+++ gcc/cp/init.c
@@ -4052,7 +4052,7 @@ build_vec_init (tree base, tree maxindex, tree init,
       tree to;
 
       for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
-      finish_for_init_stmt (for_stmt);
+      finish_init_stmt (for_stmt);
       finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator,
 			       build_int_cst (TREE_TYPE (iterator), -1)),
 		       for_stmt, false);
diff --git gcc/cp/name-lookup.c gcc/cp/name-lookup.c
index 1bce63b..9e84a1b 100644
--- gcc/cp/name-lookup.c
+++ gcc/cp/name-lookup.c
@@ -1156,7 +1156,7 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 		   }
 		}
 	      /* Error if redeclaring a local declared in a
-		 for-init-statement or in the condition of an if or
+		 init-statement or in the condition of an if or
 		 switch statement when the new declaration is in the
 		 outermost block of the controlled statement.
 		 Redeclaring a variable from a for or while condition is
diff --git gcc/cp/name-lookup.h gcc/cp/name-lookup.h
index 2cb129c..fd71038 100644
--- gcc/cp/name-lookup.h
+++ gcc/cp/name-lookup.h
@@ -107,7 +107,7 @@ enum scope_kind {
   sk_try,	     /* A try-block.  */
   sk_catch,	     /* A catch-block.  */
   sk_for,	     /* The scope of the variable declared in a
-			for-init-statement.  */
+			init-statement.  */
   sk_cond,	     /* The scope of the variable declared in the condition
 			of an if or switch statement.  */
   sk_function_parms, /* The scope containing function parameters.  */
diff --git gcc/cp/parser.c gcc/cp/parser.c
index 683a6dd..f3dc359 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -2117,7 +2117,7 @@ static tree cp_parser_condition
   (cp_parser *);
 static tree cp_parser_iteration_statement
   (cp_parser *, bool *, bool);
-static bool cp_parser_for_init_statement
+static bool cp_parser_init_statement
   (cp_parser *, tree *decl);
 static tree cp_parser_for
   (cp_parser *, bool);
@@ -2642,6 +2642,8 @@ static bool cp_parser_compound_literal_p
   (cp_parser *);
 static bool cp_parser_array_designator_p
   (cp_parser *);
+static bool cp_parser_init_statement_p
+  (cp_parser *);
 static bool cp_parser_skip_to_closing_square_bracket
   (cp_parser *);
 
@@ -10396,6 +10398,10 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
     declaration-statement
     attribute-specifier-seq (opt) try-block
 
+  init-statement:
+    expression-statement
+    simple-declaration
+
   TM Extension:
 
    statement:
@@ -10936,12 +10942,32 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
     }
 }
 
+/* Return true if we're looking at (init; cond), false otherwise.  */
+
+static bool
+cp_parser_init_statement_p (cp_parser *parser)
+{
+  /* Save tokens so that we can put them back.  */
+  cp_lexer_save_tokens (parser->lexer);
+
+  /* Look for ';' that is not nested in () or {}.  */
+  int ret = cp_parser_skip_to_closing_parenthesis_1 (parser,
+						     /*recovering=*/false,
+						     CPP_SEMICOLON,
+						     /*consume_paren=*/false);
+
+  /* Roll back the tokens we skipped.  */
+  cp_lexer_rollback_tokens (parser->lexer);
+
+  return ret == -1;
+}
+
 /* Parse a selection-statement.
 
    selection-statement:
-     if ( condition ) statement
-     if ( condition ) statement else statement
-     switch ( condition ) statement
+     if ( init-statement [opt] condition ) statement
+     if ( init-statement [opt] condition ) statement else statement
+     switch ( init-statement [opt] condition ) statement
 
    Returns the new IF_STMT or SWITCH_STMT.
 
@@ -11006,6 +11032,17 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p,
 	else
 	  statement = begin_switch_stmt ();
 
+	/* Parse the optional init-statement.  */
+	if (cp_parser_init_statement_p (parser))
+	  {
+	    tree decl;
+	    if (cxx_dialect < cxx1z)
+	      pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0,
+		       "init-statement in selection statements only available "
+		       "with -std=c++1z or -std=gnu++1z");
+	    cp_parser_init_statement (parser, &decl);
+	  }
+
 	/* Parse the condition.  */
 	condition = cp_parser_condition (parser);
 	/* Look for the `)'.  */
@@ -11306,7 +11343,7 @@ cp_parser_for (cp_parser *parser, bool ivdep)
   scope = begin_for_scope (&init);
 
   /* Parse the initialization.  */
-  is_range_for = cp_parser_for_init_statement (parser, &decl);
+  is_range_for = cp_parser_init_statement (parser, &decl);
 
   if (is_range_for)
     return cp_parser_range_for (parser, scope, init, decl, ivdep);
@@ -11323,9 +11360,9 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
   tree stmt;
 
   stmt = begin_for_stmt (scope, init);
-  /* The for-init-statement has already been parsed in
-     cp_parser_for_init_statement, so no work is needed here.  */
-  finish_for_init_stmt (stmt);
+  /* The init-statement has already been parsed in
+     cp_parser_init_statement, so no work is needed here.  */
+  finish_init_stmt (stmt);
 
   /* If there's a condition, process it.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
@@ -11354,7 +11391,7 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
     decl-specifier-seq declarator : expression
 
   The decl-specifier-seq declarator and the `:' are already parsed by
-  cp_parser_for_init_statement. If processing_template_decl it returns a
+  cp_parser_init_statement.  If processing_template_decl it returns a
   newly created RANGE_FOR_STMT; if not, it is converted to a
   regular FOR_STMT.  */
 
@@ -11552,7 +11589,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
 		  /*is_constant_init*/false, NULL_TREE,
 		  LOOKUP_ONLYCONVERTING);
 
-  finish_for_init_stmt (statement);
+  finish_init_stmt (statement);
 
   /* The new for condition.  */
   condition = build_x_binary_op (input_location, NE_EXPR,
@@ -11726,7 +11763,7 @@ cp_parser_range_for_member_function (tree range, tree identifier)
    iteration-statement:
      while ( condition ) statement
      do statement while ( expression ) ;
-     for ( for-init-statement condition [opt] ; expression [opt] )
+     for ( init-statement condition [opt] ; expression [opt] )
        statement
 
    Returns the new WHILE_STMT, DO_STMT, FOR_STMT or RANGE_FOR_STMT.  */
@@ -11832,15 +11869,15 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep)
   return statement;
 }
 
-/* Parse a for-init-statement or the declarator of a range-based-for.
+/* Parse a init-statement or the declarator of a range-based-for.
    Returns true if a range-based-for declaration is seen.
 
-   for-init-statement:
+   init-statement:
      expression-statement
      simple-declaration  */
 
 static bool
-cp_parser_for_init_statement (cp_parser* parser, tree *decl)
+cp_parser_init_statement (cp_parser* parser, tree *decl)
 {
   /* If the next token is a `;', then we have an empty
      expression-statement.  Grammatically, this is also a
diff --git gcc/cp/pt.c gcc/cp/pt.c
index e6b1368..e6bacdf 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -14974,7 +14974,7 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree orig_declv,
   if (init && TREE_CODE (init) == DECL_EXPR)
     {
       /* We need to jump through some hoops to handle declarations in the
-	 for-init-statement, since we might need to handle auto deduction,
+	 init-statement, since we might need to handle auto deduction,
 	 but we need to keep control of initialization.  */
       decl_expr = init;
       init = DECL_INITIAL (DECL_EXPR_DECL (init));
@@ -15359,7 +15359,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case FOR_STMT:
       stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
       RECUR (FOR_INIT_STMT (t));
-      finish_for_init_stmt (stmt);
+      finish_init_stmt (stmt);
       tmp = RECUR (FOR_COND (t));
       finish_for_cond (tmp, stmt, false);
       tmp = RECUR (FOR_EXPR (t));
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index 1d8f336..cae5afc 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -953,11 +953,11 @@ begin_for_stmt (tree scope, tree init)
   return r;
 }
 
-/* Finish the for-init-statement of a for-statement, which may be
+/* Finish the init-statement of a for-statement, which may be
    given by FOR_STMT.  */
 
 void
-finish_for_init_stmt (tree for_stmt)
+finish_init_stmt (tree for_stmt)
 {
   if (processing_template_decl)
     FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement1.C gcc/testsuite/g++.dg/cpp1z/init-statement1.C
index e69de29..fbe0d8b 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement1.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement1.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+extern int foo (void);
+extern void bar (int);
+
+void
+f (void)
+{
+  if (auto p = foo (); p > 10) // { dg-warning "init-statement" "" { target c++14_down } }
+    bar (p);
+  else
+    bar (-p);
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement2.C gcc/testsuite/g++.dg/cpp1z/init-statement2.C
index e69de29..8cfe1ab 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement2.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement2.C
@@ -0,0 +1,62 @@
+// { dg-options -std=c++1z }
+// Test C++17 selection statements with initializer, basic use.
+
+extern int foo (void);
+extern void bar (int);
+extern int g;
+
+void
+f (void)
+{
+  if (auto p = foo (); p > 10)
+    bar (p);
+  else
+    bar (-p);
+
+  if ((g += 2); g > 6)
+    bar (1);
+
+  if (auto a = 9, b = foo (); a + b > 10)
+    bar (a + b);
+  else
+    bar (a - b);
+
+  if (({ int a; 1;}))
+    bar (0);
+
+  if (auto i = foo (); i > 6)
+    bar (0);
+  else if (i++; i > 8)
+    bar (1);
+}
+
+extern void lock (void);
+
+void
+f2 (int i)
+{
+  if (lock (); i > 10)
+    ++i;
+  else
+    --i;
+}
+
+void
+f3 (int i)
+{
+  switch (i *= 2; auto idx = i)
+    {
+    case 4:
+      bar (3);
+      break;
+    default:
+      break;
+    }
+}
+
+void
+f4 (void)
+{
+  if constexpr (constexpr auto s = sizeof (int); s > 10)
+    foo ();
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement3.C gcc/testsuite/g++.dg/cpp1z/init-statement3.C
index e69de29..c178eaf 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement3.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement3.C
@@ -0,0 +1,16 @@
+// { dg-do run }
+// { dg-options -std=c++1z }
+// Test C++17 selection statements with initializer, side-effects.
+
+int
+main ()
+{
+  int g = 0;
+
+  if (g++; g > 1)
+    __builtin_abort ();
+  if (++g; g > 2)
+    __builtin_abort ();
+  if (g != 2)
+    __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement4.C gcc/testsuite/g++.dg/cpp1z/init-statement4.C
index e69de29..a5f7d8b 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement4.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement4.C
@@ -0,0 +1,59 @@
+// { dg-options -std=c++1z }
+
+extern int foo (void);
+extern void bar (int), die (void);
+
+void
+f (void)
+{
+  if (auto i = foo (); i != -1)
+    bar (1);
+  else
+    die ();
+
+  i = 10; // { dg-error "not declared" }
+}
+
+void
+f2 (void)
+{
+  switch (auto i = foo (); i)
+    {
+    case 0:
+      bar (i + 1);
+      break;
+    case 1:
+      bar (i + 10);
+      break;
+    default:
+      break;
+    }
+
+  i = 10; // { dg-error "not declared" }
+}
+
+void
+f3 (void)
+{
+  if constexpr (constexpr auto i = sizeof (long); i < 2)
+    die ();
+  i = 4; // { dg-error "not declared" }
+}
+
+
+void
+f4 (void)
+{
+  {
+    if (auto i = foo (); i > -1)
+      {
+	if (i > 5)
+	  bar (i);
+	if (auto j = foo (); true)
+	  j++;
+	j--; // { dg-error "not declared" }
+      }
+    i = 10; // { dg-error "not declared" }
+  }
+  i = 10; // { dg-error "not declared" }
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement5.C gcc/testsuite/g++.dg/cpp1z/init-statement5.C
index e69de29..6efa0ed 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement5.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement5.C
@@ -0,0 +1,16 @@
+// Testcase from P0305R1
+// { dg-options -std=c++1z }
+
+enum class status_code { SUCCESS };
+extern int get_value ();
+status_code bar (int);
+status_code do_more_stuff (void);
+
+status_code
+foo ()
+{
+  int n = get_value ();
+  if (status_code c = bar (n); c != status_code::SUCCESS) { return c; }
+  if (status_code c = do_more_stuff (); c != status_code::SUCCESS) { return c; }
+  return status_code::SUCCESS;
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement6.C gcc/testsuite/g++.dg/cpp1z/init-statement6.C
index e69de29..53b0d31 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement6.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement6.C
@@ -0,0 +1,25 @@
+// Testcase from P0305R1
+// { dg-options -std=c++1z }
+
+#include <string>
+#include <map>
+#include <algorithm>
+
+std::map<int, std::string> m;
+extern int xread (int *);
+extern void publish (int), raise (int);
+
+void
+foo ()
+{
+  if (auto it = m.find (10); it != m.end ()) { std::string s = it->second; }
+  if (char buf[10]; std::fgets(buf, 10, stdin)) { m[0] += buf; }
+  if (int s; int count = xread (&s)) { publish(count); raise(s); }
+
+  const char *s;
+  if (auto keywords = {"if", "for", "while"};
+      std::any_of(keywords.begin(), keywords.end(), [&s](const char* kw) { return s == kw; }))
+    {
+      // whatever
+    }
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement7.C gcc/testsuite/g++.dg/cpp1z/init-statement7.C
index e69de29..a67617e 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement7.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement7.C
@@ -0,0 +1,9 @@
+// { dg-do run }
+// { dg-options -std=c++1z }
+
+int
+main ()
+{
+  if (int i = 10, &ir = i; [=]{ return ir; }() != 10)
+    __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement8.C gcc/testsuite/g++.dg/cpp1z/init-statement8.C
index e69de29..fb40df0 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement8.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement8.C
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1z }
+
+int
+f ()
+{
+  if (int c = 5;
+      int c = 5) // { dg-error "redeclaration" }
+    return 5;
+  return 0;
+}

	Marek

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: C++ PATCH for C++17 selection statements with initializer
  2016-10-05 15:29   ` Marek Polacek
@ 2016-10-05 16:12     ` Jason Merrill
  2016-10-05 17:10       ` Marek Polacek
  0 siblings, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2016-10-05 16:12 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Wed, Oct 5, 2016 at 11:29 AM, Marek Polacek <polacek@redhat.com> wrote:
> On Wed, Oct 05, 2016 at 10:48:19AM -0400, Jason Merrill wrote:
>> On Wed, Oct 5, 2016 at 9:14 AM, Marek Polacek <polacek@redhat.com> wrote:
>> > +/* Return true if we're looking at (init; cond), false otherwise.  */
>> > +
>> > +static bool
>> > +cp_parser_init_statement_p (cp_parser *parser)
>> > +{
>> > +  unsigned paren_depth = 0;
>> > +  unsigned brace_depth = 0;
>>
>> Do we really need another one of these token scanning functions?
>> Can't you write this in terms of
>> cp_parser_skip_to_closing_parenthesis?
>>
>> > +       /* Parse the optional init-statement.  */
>> > +       tree decl;
>> > +       cp_lexer_save_tokens (parser->lexer);
>> > +       const bool init_stmt_p = cp_parser_init_statement_p (parser);
>> > +       /* Roll back the tokens we skipped.  */
>> > +       cp_lexer_rollback_tokens (parser->lexer);
>>
>> The save/rollback should be in the the predicate function, not the caller.
>
> How about the version I just posted, i.e.
> <https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00252.html>?

That doesn't address my first comment.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: C++ PATCH for C++17 selection statements with initializer
  2016-10-05 14:48 ` Jason Merrill
@ 2016-10-05 15:29   ` Marek Polacek
  2016-10-05 16:12     ` Jason Merrill
  0 siblings, 1 reply; 10+ messages in thread
From: Marek Polacek @ 2016-10-05 15:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Wed, Oct 05, 2016 at 10:48:19AM -0400, Jason Merrill wrote:
> On Wed, Oct 5, 2016 at 9:14 AM, Marek Polacek <polacek@redhat.com> wrote:
> > +/* Return true if we're looking at (init; cond), false otherwise.  */
> > +
> > +static bool
> > +cp_parser_init_statement_p (cp_parser *parser)
> > +{
> > +  unsigned paren_depth = 0;
> > +  unsigned brace_depth = 0;
> 
> Do we really need another one of these token scanning functions?
> Can't you write this in terms of
> cp_parser_skip_to_closing_parenthesis?
> 
> > +       /* Parse the optional init-statement.  */
> > +       tree decl;
> > +       cp_lexer_save_tokens (parser->lexer);
> > +       const bool init_stmt_p = cp_parser_init_statement_p (parser);
> > +       /* Roll back the tokens we skipped.  */
> > +       cp_lexer_rollback_tokens (parser->lexer);
> 
> The save/rollback should be in the the predicate function, not the caller.

How about the version I just posted, i.e.
<https://gcc.gnu.org/ml/gcc-patches/2016-10/msg00252.html>?

	Marek

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: C++ PATCH for C++17 selection statements with initializer
  2016-10-05 13:32 ` Jakub Jelinek
@ 2016-10-05 15:27   ` Marek Polacek
  0 siblings, 0 replies; 10+ messages in thread
From: Marek Polacek @ 2016-10-05 15:27 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, GCC Patches

On Wed, Oct 05, 2016 at 03:31:51PM +0200, Jakub Jelinek wrote:
> On Wed, Oct 05, 2016 at 03:14:25PM +0200, Marek Polacek wrote:
> > This is my attempt to implement P0305R1, Selection statements with initializer.
> > It allows the users to write
> > 
> >   if (init; cond) // ...
> > 
> > which is equivalent to
> > 
> >   {
> >     init
> >     if (cond) // ...
> >   }
> 
> Well, it isn't exactly equivalent, because unlike { init; if (cond) /* ... */; }
> there aren't two scopes, but just one.  So I'd say you should have tests

It was basically a quote from the standard.

> that verify that init and cond are indeed in the same scope, e.g. by trying
> something like if (int c = 5; int c = 5) ... and verifying dg-error is
> reported.

This works as expected -- with a "redeclaration" error.  I've added a test.

> > +	case CPP_CLOSE_PAREN:
> > +	  /* If the next token is a non-nested '(', then we have reached
> > +	     the end of the if condition.  */
> 
> Looks like typo, shouldn't that be ')' ?

Ah, yes.
 
> Also, do you really need two counters?
> 
> > +	  if (paren_depth-- == 0)
> > +	    return false;
> > +	  break;
> > +
> > +	case CPP_OPEN_PAREN:
> > +	  ++paren_depth;
> > +	  break;
> > +
> > +	case CPP_CLOSE_BRACE:
> > +	  --brace_depth;
> 
> I mean, shouldn't you also stop before } when seeing if (int a = }; b)
> rather than wrapping around?
 
Ok, one counter seems to work too.  Fixed.

> > +      /* Consume the token.  */
> > +      cp_lexer_consume_token (parser->lexer);
> > +    }
> 
> Also, do you really need to consume all the tokens and then rollback, rather
> than just use peek_nth_token with the index increasing in each iteration?

Here I followed cp_parser_compound_literal_p and cp_parser_array_designator_p.
But since I only read token, sure, I can do what you suggest.

Anything else?

Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk?

2016-10-05  Marek Polacek  <polacek@redhat.com>

	Implement P0305R1, Selection statements with initializer.
	* cp-array-notation.c (create_an_loop): Call finish_init_stmt
	instead of finish_for_init_stmt.
	* cp-tree.h (finish_for_init_stmt): Rename to finish_init_stmt.
	* decl.c (poplevel): Adjust a comment.
	* init.c (build_vec_init): Call finish_init_stmt instead of
	finish_for_init_stmt.
	* name-lookup.c (pushdecl_maybe_friend_1): Adjust a comment.
	* name-lookup.h (enum scope_kind): Likewise.
	* parser.c (cp_parser_statement): Update commentary.
	(cp_parser_init_statement_p): New function.
	(cp_parser_selection_statement): Parse the optional init-statement.
	(cp_parser_for): Call finish_init_stmt instead of finish_for_init_stmt.
	(cp_parser_c_for): Likewise.
	(cp_convert_range_for): Call finish_init_stmt instead of finish_for_init_stmt.
	(cp_parser_range_for_member_function): Update commentary.
	(cp_parser_iteration_statement):
	(cp_parser_for_init_statement): Rename to cp_parser_init_statement.
	* pt.c (tsubst_omp_for_iterator): Update commentary.
	(tsubst_expr): Call finish_init_stmt instead of finish_for_init_stmt.
	* semantics.c (finish_for_init_stmt): Rename to finish_init_stmt.
	Update commentary.

	* g++.dg/cpp1z/init-statement1.C: New test.
	* g++.dg/cpp1z/init-statement2.C: New test.
	* g++.dg/cpp1z/init-statement3.C: New test.
	* g++.dg/cpp1z/init-statement4.C: New test.
	* g++.dg/cpp1z/init-statement5.C: New test.
	* g++.dg/cpp1z/init-statement6.C: New test.
	* g++.dg/cpp1z/init-statement7.C: New test.
	* g++.dg/cpp1z/init-statement8.C: New test.

diff --git gcc/cp/cp-array-notation.c gcc/cp/cp-array-notation.c
index 4687ced..633ab09 100644
--- gcc/cp/cp-array-notation.c
+++ gcc/cp/cp-array-notation.c
@@ -66,7 +66,7 @@ create_an_loop (tree init, tree cond, tree incr, tree body)
 
   finish_expr_stmt (init);
   for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
-  finish_for_init_stmt (for_stmt);
+  finish_init_stmt (for_stmt);
   finish_for_cond (cond, for_stmt, false);
   finish_for_expr (incr, for_stmt);
   finish_expr_stmt (body);
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 3fbe1d9..92e4017 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -6297,7 +6297,7 @@ extern void finish_do_stmt			(tree, tree, bool);
 extern tree finish_return_stmt			(tree);
 extern tree begin_for_scope			(tree *);
 extern tree begin_for_stmt			(tree, tree);
-extern void finish_for_init_stmt		(tree);
+extern void finish_init_stmt			(tree);
 extern void finish_for_cond			(tree, tree, bool);
 extern void finish_for_expr			(tree, tree);
 extern void finish_for_stmt			(tree);
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 6646062..6a08d8f 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -639,9 +639,8 @@ poplevel (int keep, int reverse, int functionbody)
       BLOCK_SUPERCONTEXT (link) = block;
 
   /* We still support the old for-scope rules, whereby the variables
-     in a for-init statement were in scope after the for-statement
-     ended.  We only use the new rules if flag_new_for_scope is
-     nonzero.  */
+     in a init statement were in scope after the for-statement ended.
+     We only use the new rules if flag_new_for_scope is nonzero.  */
   leaving_for_scope
     = current_binding_level->kind == sk_for && flag_new_for_scope == 1;
 
diff --git gcc/cp/init.c gcc/cp/init.c
index 2d5877d..d1c8274 100644
--- gcc/cp/init.c
+++ gcc/cp/init.c
@@ -4052,7 +4052,7 @@ build_vec_init (tree base, tree maxindex, tree init,
       tree to;
 
       for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
-      finish_for_init_stmt (for_stmt);
+      finish_init_stmt (for_stmt);
       finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator,
 			       build_int_cst (TREE_TYPE (iterator), -1)),
 		       for_stmt, false);
diff --git gcc/cp/name-lookup.c gcc/cp/name-lookup.c
index 1bce63b..9e84a1b 100644
--- gcc/cp/name-lookup.c
+++ gcc/cp/name-lookup.c
@@ -1156,7 +1156,7 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 		   }
 		}
 	      /* Error if redeclaring a local declared in a
-		 for-init-statement or in the condition of an if or
+		 init-statement or in the condition of an if or
 		 switch statement when the new declaration is in the
 		 outermost block of the controlled statement.
 		 Redeclaring a variable from a for or while condition is
diff --git gcc/cp/name-lookup.h gcc/cp/name-lookup.h
index 2cb129c..fd71038 100644
--- gcc/cp/name-lookup.h
+++ gcc/cp/name-lookup.h
@@ -107,7 +107,7 @@ enum scope_kind {
   sk_try,	     /* A try-block.  */
   sk_catch,	     /* A catch-block.  */
   sk_for,	     /* The scope of the variable declared in a
-			for-init-statement.  */
+			init-statement.  */
   sk_cond,	     /* The scope of the variable declared in the condition
 			of an if or switch statement.  */
   sk_function_parms, /* The scope containing function parameters.  */
diff --git gcc/cp/parser.c gcc/cp/parser.c
index 683a6dd..8a9a011 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -2117,7 +2117,7 @@ static tree cp_parser_condition
   (cp_parser *);
 static tree cp_parser_iteration_statement
   (cp_parser *, bool *, bool);
-static bool cp_parser_for_init_statement
+static bool cp_parser_init_statement
   (cp_parser *, tree *decl);
 static tree cp_parser_for
   (cp_parser *, bool);
@@ -2642,6 +2642,8 @@ static bool cp_parser_compound_literal_p
   (cp_parser *);
 static bool cp_parser_array_designator_p
   (cp_parser *);
+static bool cp_parser_init_statement_p
+  (cp_parser *);
 static bool cp_parser_skip_to_closing_square_bracket
   (cp_parser *);
 
@@ -10396,6 +10398,10 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
     declaration-statement
     attribute-specifier-seq (opt) try-block
 
+  init-statement:
+    expression-statement
+    simple-declaration
+
   TM Extension:
 
    statement:
@@ -10936,12 +10942,54 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
     }
 }
 
+/* Return true if we're looking at (init; cond), false otherwise.  */
+
+static bool
+cp_parser_init_statement_p (cp_parser *parser)
+{
+  unsigned int depth = 0;
+  cp_token *token;
+
+  /* Look for ';' that is not nested in () or {}.  */
+  for (size_t n = 1; (token = cp_lexer_peek_nth_token (parser->lexer, n)); n++)
+    switch (token->type)
+      {
+      case CPP_EOF:
+      case CPP_PRAGMA_EOL:
+	/* If we've run out of tokens, stop.  */
+	return false;
+
+      case CPP_SEMICOLON:
+	if (depth == 0)
+	  return true;
+	break;
+
+      case CPP_CLOSE_PAREN:
+      case CPP_CLOSE_BRACE:
+	/* If the next token is a non-nested ')' or '}', then we have reached
+	   the end of the if condition.  */
+	if (depth-- == 0)
+	  return false;
+	break;
+
+      case CPP_OPEN_PAREN:
+      case CPP_OPEN_BRACE:
+	++depth;
+	break;
+
+      default:
+	break;
+      }
+
+  return false;
+}
+
 /* Parse a selection-statement.
 
    selection-statement:
-     if ( condition ) statement
-     if ( condition ) statement else statement
-     switch ( condition ) statement
+     if ( init-statement [opt] condition ) statement
+     if ( init-statement [opt] condition ) statement else statement
+     switch ( init-statement [opt] condition ) statement
 
    Returns the new IF_STMT or SWITCH_STMT.
 
@@ -11006,6 +11054,17 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p,
 	else
 	  statement = begin_switch_stmt ();
 
+	/* Parse the optional init-statement.  */
+	if (cp_parser_init_statement_p (parser))
+	  {
+	    tree decl;
+	    if (cxx_dialect < cxx1z)
+	      pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0,
+		       "init-statement in selection statements only available "
+		       "with -std=c++1z or -std=gnu++1z");
+	    cp_parser_init_statement (parser, &decl);
+	  }
+
 	/* Parse the condition.  */
 	condition = cp_parser_condition (parser);
 	/* Look for the `)'.  */
@@ -11306,7 +11365,7 @@ cp_parser_for (cp_parser *parser, bool ivdep)
   scope = begin_for_scope (&init);
 
   /* Parse the initialization.  */
-  is_range_for = cp_parser_for_init_statement (parser, &decl);
+  is_range_for = cp_parser_init_statement (parser, &decl);
 
   if (is_range_for)
     return cp_parser_range_for (parser, scope, init, decl, ivdep);
@@ -11323,9 +11382,9 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
   tree stmt;
 
   stmt = begin_for_stmt (scope, init);
-  /* The for-init-statement has already been parsed in
-     cp_parser_for_init_statement, so no work is needed here.  */
-  finish_for_init_stmt (stmt);
+  /* The init-statement has already been parsed in
+     cp_parser_init_statement, so no work is needed here.  */
+  finish_init_stmt (stmt);
 
   /* If there's a condition, process it.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
@@ -11354,7 +11413,7 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
     decl-specifier-seq declarator : expression
 
   The decl-specifier-seq declarator and the `:' are already parsed by
-  cp_parser_for_init_statement. If processing_template_decl it returns a
+  cp_parser_init_statement.  If processing_template_decl it returns a
   newly created RANGE_FOR_STMT; if not, it is converted to a
   regular FOR_STMT.  */
 
@@ -11552,7 +11611,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
 		  /*is_constant_init*/false, NULL_TREE,
 		  LOOKUP_ONLYCONVERTING);
 
-  finish_for_init_stmt (statement);
+  finish_init_stmt (statement);
 
   /* The new for condition.  */
   condition = build_x_binary_op (input_location, NE_EXPR,
@@ -11726,7 +11785,7 @@ cp_parser_range_for_member_function (tree range, tree identifier)
    iteration-statement:
      while ( condition ) statement
      do statement while ( expression ) ;
-     for ( for-init-statement condition [opt] ; expression [opt] )
+     for ( init-statement condition [opt] ; expression [opt] )
        statement
 
    Returns the new WHILE_STMT, DO_STMT, FOR_STMT or RANGE_FOR_STMT.  */
@@ -11832,15 +11891,15 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep)
   return statement;
 }
 
-/* Parse a for-init-statement or the declarator of a range-based-for.
+/* Parse a init-statement or the declarator of a range-based-for.
    Returns true if a range-based-for declaration is seen.
 
-   for-init-statement:
+   init-statement:
      expression-statement
      simple-declaration  */
 
 static bool
-cp_parser_for_init_statement (cp_parser* parser, tree *decl)
+cp_parser_init_statement (cp_parser* parser, tree *decl)
 {
   /* If the next token is a `;', then we have an empty
      expression-statement.  Grammatically, this is also a
diff --git gcc/cp/pt.c gcc/cp/pt.c
index e6b1368..e6bacdf 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -14974,7 +14974,7 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree orig_declv,
   if (init && TREE_CODE (init) == DECL_EXPR)
     {
       /* We need to jump through some hoops to handle declarations in the
-	 for-init-statement, since we might need to handle auto deduction,
+	 init-statement, since we might need to handle auto deduction,
 	 but we need to keep control of initialization.  */
       decl_expr = init;
       init = DECL_INITIAL (DECL_EXPR_DECL (init));
@@ -15359,7 +15359,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case FOR_STMT:
       stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
       RECUR (FOR_INIT_STMT (t));
-      finish_for_init_stmt (stmt);
+      finish_init_stmt (stmt);
       tmp = RECUR (FOR_COND (t));
       finish_for_cond (tmp, stmt, false);
       tmp = RECUR (FOR_EXPR (t));
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index 1d8f336..cae5afc 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -953,11 +953,11 @@ begin_for_stmt (tree scope, tree init)
   return r;
 }
 
-/* Finish the for-init-statement of a for-statement, which may be
+/* Finish the init-statement of a for-statement, which may be
    given by FOR_STMT.  */
 
 void
-finish_for_init_stmt (tree for_stmt)
+finish_init_stmt (tree for_stmt)
 {
   if (processing_template_decl)
     FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement1.C gcc/testsuite/g++.dg/cpp1z/init-statement1.C
index e69de29..fbe0d8b 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement1.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement1.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+extern int foo (void);
+extern void bar (int);
+
+void
+f (void)
+{
+  if (auto p = foo (); p > 10) // { dg-warning "init-statement" "" { target c++14_down } }
+    bar (p);
+  else
+    bar (-p);
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement2.C gcc/testsuite/g++.dg/cpp1z/init-statement2.C
index e69de29..8cfe1ab 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement2.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement2.C
@@ -0,0 +1,62 @@
+// { dg-options -std=c++1z }
+// Test C++17 selection statements with initializer, basic use.
+
+extern int foo (void);
+extern void bar (int);
+extern int g;
+
+void
+f (void)
+{
+  if (auto p = foo (); p > 10)
+    bar (p);
+  else
+    bar (-p);
+
+  if ((g += 2); g > 6)
+    bar (1);
+
+  if (auto a = 9, b = foo (); a + b > 10)
+    bar (a + b);
+  else
+    bar (a - b);
+
+  if (({ int a; 1;}))
+    bar (0);
+
+  if (auto i = foo (); i > 6)
+    bar (0);
+  else if (i++; i > 8)
+    bar (1);
+}
+
+extern void lock (void);
+
+void
+f2 (int i)
+{
+  if (lock (); i > 10)
+    ++i;
+  else
+    --i;
+}
+
+void
+f3 (int i)
+{
+  switch (i *= 2; auto idx = i)
+    {
+    case 4:
+      bar (3);
+      break;
+    default:
+      break;
+    }
+}
+
+void
+f4 (void)
+{
+  if constexpr (constexpr auto s = sizeof (int); s > 10)
+    foo ();
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement3.C gcc/testsuite/g++.dg/cpp1z/init-statement3.C
index e69de29..c178eaf 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement3.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement3.C
@@ -0,0 +1,16 @@
+// { dg-do run }
+// { dg-options -std=c++1z }
+// Test C++17 selection statements with initializer, side-effects.
+
+int
+main ()
+{
+  int g = 0;
+
+  if (g++; g > 1)
+    __builtin_abort ();
+  if (++g; g > 2)
+    __builtin_abort ();
+  if (g != 2)
+    __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement4.C gcc/testsuite/g++.dg/cpp1z/init-statement4.C
index e69de29..a5f7d8b 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement4.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement4.C
@@ -0,0 +1,59 @@
+// { dg-options -std=c++1z }
+
+extern int foo (void);
+extern void bar (int), die (void);
+
+void
+f (void)
+{
+  if (auto i = foo (); i != -1)
+    bar (1);
+  else
+    die ();
+
+  i = 10; // { dg-error "not declared" }
+}
+
+void
+f2 (void)
+{
+  switch (auto i = foo (); i)
+    {
+    case 0:
+      bar (i + 1);
+      break;
+    case 1:
+      bar (i + 10);
+      break;
+    default:
+      break;
+    }
+
+  i = 10; // { dg-error "not declared" }
+}
+
+void
+f3 (void)
+{
+  if constexpr (constexpr auto i = sizeof (long); i < 2)
+    die ();
+  i = 4; // { dg-error "not declared" }
+}
+
+
+void
+f4 (void)
+{
+  {
+    if (auto i = foo (); i > -1)
+      {
+	if (i > 5)
+	  bar (i);
+	if (auto j = foo (); true)
+	  j++;
+	j--; // { dg-error "not declared" }
+      }
+    i = 10; // { dg-error "not declared" }
+  }
+  i = 10; // { dg-error "not declared" }
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement5.C gcc/testsuite/g++.dg/cpp1z/init-statement5.C
index e69de29..6efa0ed 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement5.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement5.C
@@ -0,0 +1,16 @@
+// Testcase from P0305R1
+// { dg-options -std=c++1z }
+
+enum class status_code { SUCCESS };
+extern int get_value ();
+status_code bar (int);
+status_code do_more_stuff (void);
+
+status_code
+foo ()
+{
+  int n = get_value ();
+  if (status_code c = bar (n); c != status_code::SUCCESS) { return c; }
+  if (status_code c = do_more_stuff (); c != status_code::SUCCESS) { return c; }
+  return status_code::SUCCESS;
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement6.C gcc/testsuite/g++.dg/cpp1z/init-statement6.C
index e69de29..53b0d31 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement6.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement6.C
@@ -0,0 +1,25 @@
+// Testcase from P0305R1
+// { dg-options -std=c++1z }
+
+#include <string>
+#include <map>
+#include <algorithm>
+
+std::map<int, std::string> m;
+extern int xread (int *);
+extern void publish (int), raise (int);
+
+void
+foo ()
+{
+  if (auto it = m.find (10); it != m.end ()) { std::string s = it->second; }
+  if (char buf[10]; std::fgets(buf, 10, stdin)) { m[0] += buf; }
+  if (int s; int count = xread (&s)) { publish(count); raise(s); }
+
+  const char *s;
+  if (auto keywords = {"if", "for", "while"};
+      std::any_of(keywords.begin(), keywords.end(), [&s](const char* kw) { return s == kw; }))
+    {
+      // whatever
+    }
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement7.C gcc/testsuite/g++.dg/cpp1z/init-statement7.C
index e69de29..a67617e 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement7.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement7.C
@@ -0,0 +1,9 @@
+// { dg-do run }
+// { dg-options -std=c++1z }
+
+int
+main ()
+{
+  if (int i = 10, &ir = i; [=]{ return ir; }() != 10)
+    __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement8.C gcc/testsuite/g++.dg/cpp1z/init-statement8.C
index e69de29..fb40df0 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement8.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement8.C
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1z }
+
+int
+f ()
+{
+  if (int c = 5;
+      int c = 5) // { dg-error "redeclaration" }
+    return 5;
+  return 0;
+}

	Marek

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: C++ PATCH for C++17 selection statements with initializer
  2016-10-05 13:14 Marek Polacek
  2016-10-05 13:32 ` Jakub Jelinek
@ 2016-10-05 14:48 ` Jason Merrill
  2016-10-05 15:29   ` Marek Polacek
  1 sibling, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2016-10-05 14:48 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Wed, Oct 5, 2016 at 9:14 AM, Marek Polacek <polacek@redhat.com> wrote:
> +/* Return true if we're looking at (init; cond), false otherwise.  */
> +
> +static bool
> +cp_parser_init_statement_p (cp_parser *parser)
> +{
> +  unsigned paren_depth = 0;
> +  unsigned brace_depth = 0;

Do we really need another one of these token scanning functions?
Can't you write this in terms of
cp_parser_skip_to_closing_parenthesis?

> +       /* Parse the optional init-statement.  */
> +       tree decl;
> +       cp_lexer_save_tokens (parser->lexer);
> +       const bool init_stmt_p = cp_parser_init_statement_p (parser);
> +       /* Roll back the tokens we skipped.  */
> +       cp_lexer_rollback_tokens (parser->lexer);

The save/rollback should be in the the predicate function, not the caller.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: C++ PATCH for C++17 selection statements with initializer
  2016-10-05 13:14 Marek Polacek
@ 2016-10-05 13:32 ` Jakub Jelinek
  2016-10-05 15:27   ` Marek Polacek
  2016-10-05 14:48 ` Jason Merrill
  1 sibling, 1 reply; 10+ messages in thread
From: Jakub Jelinek @ 2016-10-05 13:32 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jason Merrill, GCC Patches

On Wed, Oct 05, 2016 at 03:14:25PM +0200, Marek Polacek wrote:
> This is my attempt to implement P0305R1, Selection statements with initializer.
> It allows the users to write
> 
>   if (init; cond) // ...
> 
> which is equivalent to
> 
>   {
>     init
>     if (cond) // ...
>   }

Well, it isn't exactly equivalent, because unlike { init; if (cond) /* ... */; }
there aren't two scopes, but just one.  So I'd say you should have tests
that verify that init and cond are indeed in the same scope, e.g. by trying
something like if (int c = 5; int c = 5) ... and verifying dg-error is
reported.

> +	case CPP_CLOSE_PAREN:
> +	  /* If the next token is a non-nested '(', then we have reached
> +	     the end of the if condition.  */

Looks like typo, shouldn't that be ')' ?

Also, do you really need two counters?

> +	  if (paren_depth-- == 0)
> +	    return false;
> +	  break;
> +
> +	case CPP_OPEN_PAREN:
> +	  ++paren_depth;
> +	  break;
> +
> +	case CPP_CLOSE_BRACE:
> +	  --brace_depth;

I mean, shouldn't you also stop before } when seeing if (int a = }; b)
rather than wrapping around?

> +      /* Consume the token.  */
> +      cp_lexer_consume_token (parser->lexer);
> +    }

Also, do you really need to consume all the tokens and then rollback, rather
than just use peek_nth_token with the index increasing in each iteration?

	Jakub

^ permalink raw reply	[flat|nested] 10+ messages in thread

* C++ PATCH for C++17 selection statements with initializer
@ 2016-10-05 13:14 Marek Polacek
  2016-10-05 13:32 ` Jakub Jelinek
  2016-10-05 14:48 ` Jason Merrill
  0 siblings, 2 replies; 10+ messages in thread
From: Marek Polacek @ 2016-10-05 13:14 UTC (permalink / raw)
  To: Jason Merrill, GCC Patches

This is my attempt to implement P0305R1, Selection statements with initializer.
It allows the users to write

  if (init; cond) // ...

which is equivalent to

  {
    init
    if (cond) // ...
  }

Similarly for if-else, if constexpr, and switch.

The approach I had taken was to tentatively parse "init" and if no semicolon
follows, abort the parse and just parse the condition.  But this didn't work.
An init-statement is either a simple-declaration or an expression-statement,
and parsing either has irreversible side-effects--e.g. adding a new statement
or a new declaration, or duplicating side-effects.  Using firewalls here
doesn't help.  Since an init-statement ends with a semicolon, I decided to
write cp_parser_init_statement_p, which checks if there's a semicolon in the if
condition that is not nested in () or in {} (think of ({}) or lambda
expressions).  It seemed a bit weird but seems to work well.  And then it's
just a simple matter of calling cp_parser_init_statement that parses either a
simple declaration or an expression statement and does the right thing wrt
scopes.

Since "for-init-statement" is no longer in the standard, I renamed all the
occurrences to "init-statement".

There's also this -ffor-scope thing, but I didn't touch it and it's probably
not necessary to.

Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk? 

2016-10-05  Marek Polacek  <polacek@redhat.com>

	Implement P0305R1, Selection statements with initializer.
	* cp-array-notation.c (create_an_loop): Call finish_init_stmt
	instead of finish_for_init_stmt.
	* cp-tree.h (finish_for_init_stmt): Rename to finish_init_stmt.
	* decl.c (poplevel): Adjust a comment.
	* init.c (build_vec_init): Call finish_init_stmt instead of
	finish_for_init_stmt.
	* name-lookup.c (pushdecl_maybe_friend_1): Adjust a comment.
	* name-lookup.h (enum scope_kind): Likewise.
	* parser.c (cp_parser_statement): Update commentary.
	(cp_parser_init_statement_p): New function.
	(cp_parser_selection_statement): Parse the optional init-statement.
	(cp_parser_for): Call finish_init_stmt instead of finish_for_init_stmt.
	(cp_parser_c_for): Likewise.
	(cp_convert_range_for): Call finish_init_stmt instead of finish_for_init_stmt.
	(cp_parser_range_for_member_function): Update commentary.
	(cp_parser_iteration_statement):
	(cp_parser_for_init_statement): Rename to cp_parser_init_statement.
	* pt.c (tsubst_omp_for_iterator): Update commentary.
	(tsubst_expr): Call finish_init_stmt instead of finish_for_init_stmt.
	* semantics.c (finish_for_init_stmt): Rename to finish_init_stmt.
	Update commentary.

	* g++.dg/cpp1z/init-statement1.C: New test.
	* g++.dg/cpp1z/init-statement2.C: New test.
	* g++.dg/cpp1z/init-statement3.C: New test.
	* g++.dg/cpp1z/init-statement4.C: New test.
	* g++.dg/cpp1z/init-statement5.C: New test.
	* g++.dg/cpp1z/init-statement6.C: New test.
	* g++.dg/cpp1z/init-statement7.C: New test.

diff --git gcc/cp/cp-array-notation.c gcc/cp/cp-array-notation.c
index 4687ced..633ab09 100644
--- gcc/cp/cp-array-notation.c
+++ gcc/cp/cp-array-notation.c
@@ -66,7 +66,7 @@ create_an_loop (tree init, tree cond, tree incr, tree body)
 
   finish_expr_stmt (init);
   for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
-  finish_for_init_stmt (for_stmt);
+  finish_init_stmt (for_stmt);
   finish_for_cond (cond, for_stmt, false);
   finish_for_expr (incr, for_stmt);
   finish_expr_stmt (body);
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 3fbe1d9..92e4017 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -6297,7 +6297,7 @@ extern void finish_do_stmt			(tree, tree, bool);
 extern tree finish_return_stmt			(tree);
 extern tree begin_for_scope			(tree *);
 extern tree begin_for_stmt			(tree, tree);
-extern void finish_for_init_stmt		(tree);
+extern void finish_init_stmt			(tree);
 extern void finish_for_cond			(tree, tree, bool);
 extern void finish_for_expr			(tree, tree);
 extern void finish_for_stmt			(tree);
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 6646062..6a08d8f 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -639,9 +639,8 @@ poplevel (int keep, int reverse, int functionbody)
       BLOCK_SUPERCONTEXT (link) = block;
 
   /* We still support the old for-scope rules, whereby the variables
-     in a for-init statement were in scope after the for-statement
-     ended.  We only use the new rules if flag_new_for_scope is
-     nonzero.  */
+     in a init statement were in scope after the for-statement ended.
+     We only use the new rules if flag_new_for_scope is nonzero.  */
   leaving_for_scope
     = current_binding_level->kind == sk_for && flag_new_for_scope == 1;
 
diff --git gcc/cp/init.c gcc/cp/init.c
index 2d5877d..d1c8274 100644
--- gcc/cp/init.c
+++ gcc/cp/init.c
@@ -4052,7 +4052,7 @@ build_vec_init (tree base, tree maxindex, tree init,
       tree to;
 
       for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
-      finish_for_init_stmt (for_stmt);
+      finish_init_stmt (for_stmt);
       finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator,
 			       build_int_cst (TREE_TYPE (iterator), -1)),
 		       for_stmt, false);
diff --git gcc/cp/name-lookup.c gcc/cp/name-lookup.c
index 1bce63b..9e84a1b 100644
--- gcc/cp/name-lookup.c
+++ gcc/cp/name-lookup.c
@@ -1156,7 +1156,7 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 		   }
 		}
 	      /* Error if redeclaring a local declared in a
-		 for-init-statement or in the condition of an if or
+		 init-statement or in the condition of an if or
 		 switch statement when the new declaration is in the
 		 outermost block of the controlled statement.
 		 Redeclaring a variable from a for or while condition is
diff --git gcc/cp/name-lookup.h gcc/cp/name-lookup.h
index 2cb129c..fd71038 100644
--- gcc/cp/name-lookup.h
+++ gcc/cp/name-lookup.h
@@ -107,7 +107,7 @@ enum scope_kind {
   sk_try,	     /* A try-block.  */
   sk_catch,	     /* A catch-block.  */
   sk_for,	     /* The scope of the variable declared in a
-			for-init-statement.  */
+			init-statement.  */
   sk_cond,	     /* The scope of the variable declared in the condition
 			of an if or switch statement.  */
   sk_function_parms, /* The scope containing function parameters.  */
diff --git gcc/cp/parser.c gcc/cp/parser.c
index 683a6dd..03c007e 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -2117,7 +2117,7 @@ static tree cp_parser_condition
   (cp_parser *);
 static tree cp_parser_iteration_statement
   (cp_parser *, bool *, bool);
-static bool cp_parser_for_init_statement
+static bool cp_parser_init_statement
   (cp_parser *, tree *decl);
 static tree cp_parser_for
   (cp_parser *, bool);
@@ -2642,6 +2642,8 @@ static bool cp_parser_compound_literal_p
   (cp_parser *);
 static bool cp_parser_array_designator_p
   (cp_parser *);
+static bool cp_parser_init_statement_p
+  (cp_parser *);
 static bool cp_parser_skip_to_closing_square_bracket
   (cp_parser *);
 
@@ -10396,6 +10398,10 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
     declaration-statement
     attribute-specifier-seq (opt) try-block
 
+  init-statement:
+    expression-statement
+    simple-declaration
+
   TM Extension:
 
    statement:
@@ -10936,12 +10942,65 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
     }
 }
 
+/* Return true if we're looking at (init; cond), false otherwise.  */
+
+static bool
+cp_parser_init_statement_p (cp_parser *parser)
+{
+  unsigned paren_depth = 0;
+  unsigned brace_depth = 0;
+
+  /* Look for ';' that is not nested in () or {}.  */
+  while (true)
+    {
+      cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+      switch (token->type)
+	{
+	case CPP_EOF:
+	case CPP_PRAGMA_EOL:
+	  /* If we've run out of tokens, stop.  */
+	  return false;
+
+	case CPP_SEMICOLON:
+	  if (paren_depth == 0 && brace_depth == 0)
+	    return true;
+	  break;
+
+	case CPP_CLOSE_PAREN:
+	  /* If the next token is a non-nested '(', then we have reached
+	     the end of the if condition.  */
+	  if (paren_depth-- == 0)
+	    return false;
+	  break;
+
+	case CPP_OPEN_PAREN:
+	  ++paren_depth;
+	  break;
+
+	case CPP_CLOSE_BRACE:
+	  --brace_depth;
+	  break;
+
+	case CPP_OPEN_BRACE:
+	  ++brace_depth;
+	  break;
+
+	default:
+	  break;
+	}
+
+      /* Consume the token.  */
+      cp_lexer_consume_token (parser->lexer);
+    }
+}
+
 /* Parse a selection-statement.
 
    selection-statement:
-     if ( condition ) statement
-     if ( condition ) statement else statement
-     switch ( condition ) statement
+     if ( init-statement [opt] condition ) statement
+     if ( init-statement [opt] condition ) statement else statement
+     switch ( init-statement [opt] condition ) statement
 
    Returns the new IF_STMT or SWITCH_STMT.
 
@@ -11006,6 +11065,21 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p,
 	else
 	  statement = begin_switch_stmt ();
 
+	/* Parse the optional init-statement.  */
+	tree decl;
+	cp_lexer_save_tokens (parser->lexer);
+	const bool init_stmt_p = cp_parser_init_statement_p (parser);
+	/* Roll back the tokens we skipped.  */
+	cp_lexer_rollback_tokens (parser->lexer);
+	if (init_stmt_p)
+	  {
+	    if (cxx_dialect < cxx1z)
+	      pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0,
+		       "init-statement in selection statements only available "
+		       "with -std=c++1z or -std=gnu++1z");
+	    cp_parser_init_statement (parser, &decl);
+	  }
+
 	/* Parse the condition.  */
 	condition = cp_parser_condition (parser);
 	/* Look for the `)'.  */
@@ -11306,7 +11380,7 @@ cp_parser_for (cp_parser *parser, bool ivdep)
   scope = begin_for_scope (&init);
 
   /* Parse the initialization.  */
-  is_range_for = cp_parser_for_init_statement (parser, &decl);
+  is_range_for = cp_parser_init_statement (parser, &decl);
 
   if (is_range_for)
     return cp_parser_range_for (parser, scope, init, decl, ivdep);
@@ -11323,9 +11397,9 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
   tree stmt;
 
   stmt = begin_for_stmt (scope, init);
-  /* The for-init-statement has already been parsed in
-     cp_parser_for_init_statement, so no work is needed here.  */
-  finish_for_init_stmt (stmt);
+  /* The init-statement has already been parsed in
+     cp_parser_init_statement, so no work is needed here.  */
+  finish_init_stmt (stmt);
 
   /* If there's a condition, process it.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
@@ -11354,7 +11428,7 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep)
     decl-specifier-seq declarator : expression
 
   The decl-specifier-seq declarator and the `:' are already parsed by
-  cp_parser_for_init_statement. If processing_template_decl it returns a
+  cp_parser_init_statement.  If processing_template_decl it returns a
   newly created RANGE_FOR_STMT; if not, it is converted to a
   regular FOR_STMT.  */
 
@@ -11552,7 +11626,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
 		  /*is_constant_init*/false, NULL_TREE,
 		  LOOKUP_ONLYCONVERTING);
 
-  finish_for_init_stmt (statement);
+  finish_init_stmt (statement);
 
   /* The new for condition.  */
   condition = build_x_binary_op (input_location, NE_EXPR,
@@ -11726,7 +11800,7 @@ cp_parser_range_for_member_function (tree range, tree identifier)
    iteration-statement:
      while ( condition ) statement
      do statement while ( expression ) ;
-     for ( for-init-statement condition [opt] ; expression [opt] )
+     for ( init-statement condition [opt] ; expression [opt] )
        statement
 
    Returns the new WHILE_STMT, DO_STMT, FOR_STMT or RANGE_FOR_STMT.  */
@@ -11832,15 +11906,15 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep)
   return statement;
 }
 
-/* Parse a for-init-statement or the declarator of a range-based-for.
+/* Parse a init-statement or the declarator of a range-based-for.
    Returns true if a range-based-for declaration is seen.
 
-   for-init-statement:
+   init-statement:
      expression-statement
      simple-declaration  */
 
 static bool
-cp_parser_for_init_statement (cp_parser* parser, tree *decl)
+cp_parser_init_statement (cp_parser* parser, tree *decl)
 {
   /* If the next token is a `;', then we have an empty
      expression-statement.  Grammatically, this is also a
diff --git gcc/cp/pt.c gcc/cp/pt.c
index e6b1368..e6bacdf 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -14974,7 +14974,7 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree orig_declv,
   if (init && TREE_CODE (init) == DECL_EXPR)
     {
       /* We need to jump through some hoops to handle declarations in the
-	 for-init-statement, since we might need to handle auto deduction,
+	 init-statement, since we might need to handle auto deduction,
 	 but we need to keep control of initialization.  */
       decl_expr = init;
       init = DECL_INITIAL (DECL_EXPR_DECL (init));
@@ -15359,7 +15359,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case FOR_STMT:
       stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
       RECUR (FOR_INIT_STMT (t));
-      finish_for_init_stmt (stmt);
+      finish_init_stmt (stmt);
       tmp = RECUR (FOR_COND (t));
       finish_for_cond (tmp, stmt, false);
       tmp = RECUR (FOR_EXPR (t));
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index 1d8f336..cae5afc 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -953,11 +953,11 @@ begin_for_stmt (tree scope, tree init)
   return r;
 }
 
-/* Finish the for-init-statement of a for-statement, which may be
+/* Finish the init-statement of a for-statement, which may be
    given by FOR_STMT.  */
 
 void
-finish_for_init_stmt (tree for_stmt)
+finish_init_stmt (tree for_stmt)
 {
   if (processing_template_decl)
     FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement1.C gcc/testsuite/g++.dg/cpp1z/init-statement1.C
index e69de29..fbe0d8b 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement1.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement1.C
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+extern int foo (void);
+extern void bar (int);
+
+void
+f (void)
+{
+  if (auto p = foo (); p > 10) // { dg-warning "init-statement" "" { target c++14_down } }
+    bar (p);
+  else
+    bar (-p);
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement2.C gcc/testsuite/g++.dg/cpp1z/init-statement2.C
index e69de29..8cfe1ab 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement2.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement2.C
@@ -0,0 +1,62 @@
+// { dg-options -std=c++1z }
+// Test C++17 selection statements with initializer, basic use.
+
+extern int foo (void);
+extern void bar (int);
+extern int g;
+
+void
+f (void)
+{
+  if (auto p = foo (); p > 10)
+    bar (p);
+  else
+    bar (-p);
+
+  if ((g += 2); g > 6)
+    bar (1);
+
+  if (auto a = 9, b = foo (); a + b > 10)
+    bar (a + b);
+  else
+    bar (a - b);
+
+  if (({ int a; 1;}))
+    bar (0);
+
+  if (auto i = foo (); i > 6)
+    bar (0);
+  else if (i++; i > 8)
+    bar (1);
+}
+
+extern void lock (void);
+
+void
+f2 (int i)
+{
+  if (lock (); i > 10)
+    ++i;
+  else
+    --i;
+}
+
+void
+f3 (int i)
+{
+  switch (i *= 2; auto idx = i)
+    {
+    case 4:
+      bar (3);
+      break;
+    default:
+      break;
+    }
+}
+
+void
+f4 (void)
+{
+  if constexpr (constexpr auto s = sizeof (int); s > 10)
+    foo ();
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement3.C gcc/testsuite/g++.dg/cpp1z/init-statement3.C
index e69de29..c178eaf 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement3.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement3.C
@@ -0,0 +1,16 @@
+// { dg-do run }
+// { dg-options -std=c++1z }
+// Test C++17 selection statements with initializer, side-effects.
+
+int
+main ()
+{
+  int g = 0;
+
+  if (g++; g > 1)
+    __builtin_abort ();
+  if (++g; g > 2)
+    __builtin_abort ();
+  if (g != 2)
+    __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement4.C gcc/testsuite/g++.dg/cpp1z/init-statement4.C
index e69de29..a5f7d8b 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement4.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement4.C
@@ -0,0 +1,59 @@
+// { dg-options -std=c++1z }
+
+extern int foo (void);
+extern void bar (int), die (void);
+
+void
+f (void)
+{
+  if (auto i = foo (); i != -1)
+    bar (1);
+  else
+    die ();
+
+  i = 10; // { dg-error "not declared" }
+}
+
+void
+f2 (void)
+{
+  switch (auto i = foo (); i)
+    {
+    case 0:
+      bar (i + 1);
+      break;
+    case 1:
+      bar (i + 10);
+      break;
+    default:
+      break;
+    }
+
+  i = 10; // { dg-error "not declared" }
+}
+
+void
+f3 (void)
+{
+  if constexpr (constexpr auto i = sizeof (long); i < 2)
+    die ();
+  i = 4; // { dg-error "not declared" }
+}
+
+
+void
+f4 (void)
+{
+  {
+    if (auto i = foo (); i > -1)
+      {
+	if (i > 5)
+	  bar (i);
+	if (auto j = foo (); true)
+	  j++;
+	j--; // { dg-error "not declared" }
+      }
+    i = 10; // { dg-error "not declared" }
+  }
+  i = 10; // { dg-error "not declared" }
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement5.C gcc/testsuite/g++.dg/cpp1z/init-statement5.C
index e69de29..6efa0ed 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement5.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement5.C
@@ -0,0 +1,16 @@
+// Testcase from P0305R1
+// { dg-options -std=c++1z }
+
+enum class status_code { SUCCESS };
+extern int get_value ();
+status_code bar (int);
+status_code do_more_stuff (void);
+
+status_code
+foo ()
+{
+  int n = get_value ();
+  if (status_code c = bar (n); c != status_code::SUCCESS) { return c; }
+  if (status_code c = do_more_stuff (); c != status_code::SUCCESS) { return c; }
+  return status_code::SUCCESS;
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement6.C gcc/testsuite/g++.dg/cpp1z/init-statement6.C
index e69de29..53b0d31 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement6.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement6.C
@@ -0,0 +1,25 @@
+// Testcase from P0305R1
+// { dg-options -std=c++1z }
+
+#include <string>
+#include <map>
+#include <algorithm>
+
+std::map<int, std::string> m;
+extern int xread (int *);
+extern void publish (int), raise (int);
+
+void
+foo ()
+{
+  if (auto it = m.find (10); it != m.end ()) { std::string s = it->second; }
+  if (char buf[10]; std::fgets(buf, 10, stdin)) { m[0] += buf; }
+  if (int s; int count = xread (&s)) { publish(count); raise(s); }
+
+  const char *s;
+  if (auto keywords = {"if", "for", "while"};
+      std::any_of(keywords.begin(), keywords.end(), [&s](const char* kw) { return s == kw; }))
+    {
+      // whatever
+    }
+}
diff --git gcc/testsuite/g++.dg/cpp1z/init-statement7.C gcc/testsuite/g++.dg/cpp1z/init-statement7.C
index e69de29..a67617e 100644
--- gcc/testsuite/g++.dg/cpp1z/init-statement7.C
+++ gcc/testsuite/g++.dg/cpp1z/init-statement7.C
@@ -0,0 +1,9 @@
+// { dg-do run }
+// { dg-options -std=c++1z }
+
+int
+main ()
+{
+  if (int i = 10, &ir = i; [=]{ return ir; }() != 10)
+    __builtin_abort ();
+}

	Marek

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2016-11-16  1:02 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-06  2:03 C++ PATCH for C++17 selection statements with initializer David Edelsohn
2016-11-16  1:02 ` Marek Polacek
  -- strict thread matches above, loose matches on Subject: below --
2016-10-05 13:14 Marek Polacek
2016-10-05 13:32 ` Jakub Jelinek
2016-10-05 15:27   ` Marek Polacek
2016-10-05 14:48 ` Jason Merrill
2016-10-05 15:29   ` Marek Polacek
2016-10-05 16:12     ` Jason Merrill
2016-10-05 17:10       ` Marek Polacek
2016-10-05 17:32         ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).