diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1d87845a882..aa1fd0c03c8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2017-01-07 Jason Merrill + + PR c++/78948 - instantiation from discarded statement + * parser.h (struct cp_parser): Remove in_discarded_stmt field. + * cp-tree.h (in_discarded_stmt): Declare it. + (struct saved_scope): Add discarded_stmt bitfield. + (in_discarded_stmt): New macro. + * decl2.c (mark_used): Check it. + * parser.c (cp_parser_selection_statement): Adjust. + (cp_parser_jump_statement): Adjust. + 2017-01-05 Jakub Jelinek PR c++/78931 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 39f5d790cdc..24de3462bb7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1281,6 +1281,10 @@ struct GTY(()) saved_scope { BOOL_BITFIELD x_processing_explicit_instantiation : 1; BOOL_BITFIELD need_pop_function_context : 1; +/* Nonzero if we are parsing the discarded statement of a constexpr + if-statement. */ + BOOL_BITFIELD discarded_stmt : 1; + int unevaluated_operand; int inhibit_evaluation_warnings; int noexcept_operand; @@ -1341,6 +1345,8 @@ extern GTY(()) struct saved_scope *scope_chain; #define processing_specialization scope_chain->x_processing_specialization #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation +#define in_discarded_stmt scope_chain->discarded_stmt + /* RAII sentinel to handle clearing processing_template_decl and restoring it when done. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index a0375ad4cc4..435f51fe564 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -5112,7 +5112,7 @@ mark_used (tree decl, tsubst_flags_t complain) } /* If we don't need a value, then we don't need to synthesize DECL. */ - if (cp_unevaluated_operand != 0) + if (cp_unevaluated_operand || in_discarded_stmt) return true; DECL_ODR_USED (decl) = 1; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 57ae0647195..e8c06424e29 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11147,12 +11147,12 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, /* Outside a template, the non-selected branch of a constexpr if is a 'discarded statement', i.e. unevaluated. */ - bool was_discarded = parser->in_discarded_stmt; + bool was_discarded = in_discarded_stmt; bool discard_then = (cx && !processing_template_decl && integer_zerop (condition)); if (discard_then) { - parser->in_discarded_stmt = true; + in_discarded_stmt = true; ++c_inhibit_evaluation_warnings; } @@ -11166,7 +11166,7 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, if (discard_then) { THEN_CLAUSE (statement) = NULL_TREE; - parser->in_discarded_stmt = was_discarded; + in_discarded_stmt = was_discarded; --c_inhibit_evaluation_warnings; } @@ -11178,7 +11178,7 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, && integer_nonzerop (condition)); if (discard_else) { - parser->in_discarded_stmt = true; + in_discarded_stmt = true; ++c_inhibit_evaluation_warnings; } @@ -11235,7 +11235,7 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, if (discard_else) { ELSE_CLAUSE (statement) = NULL_TREE; - parser->in_discarded_stmt = was_discarded; + in_discarded_stmt = was_discarded; --c_inhibit_evaluation_warnings; } } @@ -12143,7 +12143,7 @@ cp_parser_jump_statement (cp_parser* parser) expression. */ expr = NULL_TREE; /* Build the return-statement. */ - if (current_function_auto_return_pattern && parser->in_discarded_stmt) + if (current_function_auto_return_pattern && in_discarded_stmt) /* Don't deduce from a discarded return statement. */; else statement = finish_return_stmt (expr); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index f242f4c6153..0994e1e7f4f 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -336,10 +336,6 @@ struct GTY(()) cp_parser { a local class. */ bool in_function_body; - /* TRUE if we are parsing a C++17 discarded statement (the non-taken branch - of an if constexpr). */ - bool in_discarded_stmt; - /* Nonzero if we're processing a __transaction_atomic or __transaction_relaxed statement. */ unsigned char in_transaction; diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if10.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if10.C new file mode 100644 index 00000000000..64de53f0603 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if10.C @@ -0,0 +1,16 @@ +// PR c++/79848 +// { dg-options -std=c++1z } + +template +void sizeof_mismatch() +{ + static_assert(T == 0, "sizeof mismatch"); +} + +int main() +{ + if constexpr(sizeof(long long) == sizeof(char*)) + ; + else + sizeof_mismatch(); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if11.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if11.C new file mode 100644 index 00000000000..1c6247e0e35 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if11.C @@ -0,0 +1,16 @@ +// Test that discarded statements differ from unevaluated operands in some +// ways. +// { dg-options -std=c++1z } + +struct A { int i; }; + +int main() +{ + if constexpr(true) + ; + else + { + []{}(); + A::i; // { dg-error "non-static" } + } +}