+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.
+
2016-10-04 Jason Merrill <jason@redhat.com>
PR c++/77852
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);
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);
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;
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);
}
}
/* 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
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. */
(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);
(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 *);
declaration-statement
attribute-specifier-seq (opt) try-block
+ init-statement:
+ expression-statement
+ simple-declaration
+
TM Extension:
statement:
}
}
+/* 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.
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 `)'. */
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);
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))
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. */
/*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,
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. */
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
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));
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));
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));
+2016-10-05 Marek Polacek <polacek@redhat.com>
+
+ * 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.
+
2016-10-05 Louis Krupp <louis.krupp@zoho.com>
PR fortran/67524
--- /dev/null
+// { 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);
+}
+// { 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);
+}
--- /dev/null
+// { 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 ();
+}
+// { 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 ();
+}
--- /dev/null
+// { 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 ();
+}
+// { 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 ();
+}
--- /dev/null
+// { 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" }
+}
+// { 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" }
+}
--- /dev/null
+// 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;
+}
+// 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;
+}
--- /dev/null
+// 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
+ }
+}
+// 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
+ }
+}
--- /dev/null
+// { dg-do run }
+// { dg-options -std=c++1z }
+
+int
+main ()
+{
+ if (int i = 10, &ir = i; [=]{ return ir; }() != 10)
+ __builtin_abort ();
+}
+// { dg-do run }
+// { dg-options -std=c++1z }
+
+int
+main ()
+{
+ if (int i = 10, &ir = i; [=]{ return ir; }() != 10)
+ __builtin_abort ();
+}
--- /dev/null
+// { dg-options -std=c++1z }
+
+int
+f ()
+{
+ if (int c = 5;
+ int c = 5) // { dg-error "redeclaration" }
+ return 5;
+ return 0;
+}
+// { dg-options -std=c++1z }
+
+int
+f ()
+{
+ if (int c = 5;
+ int c = 5) // { dg-error "redeclaration" }
+ return 5;
+ return 0;
+}