This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PR c++/84263] GC ICE with decltype
- From: Nathan Sidwell <nathan at acm dot org>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Martin Liška <mliska at suse dot cz>
- Date: Thu, 8 Feb 2018 11:29:23 -0500
- Subject: [PR c++/84263] GC ICE with decltype
- Authentication-results: sourceware.org; auth=none
This patch fixes 84263, a GC breakage entirely unconnected with the
patch of mine that exposed it. I guess I perturbed the memory layout
sufficiently to tickle it -- on a 32bit host.
The underlying problem is that decltype parsing has to squirrel away
some data in the same manner to template-ids. But it was failing to
push and pop the deferring access stack. That meant it stashed its own
deferred accesses, but they also remained on the stack. A subsequent
deferred access could reallocate the vector of accesses there, if a
subsequent access needed deferring. That reallocation proceeds by
gc_alloc/gc_free. The gc_free frees the original set, which is what we
had stashed away. All is well until we try and GC things, with that
token still live. Boom!
Fixed by pushing and popping the access stack. I also reorganized the
code to use the modern construct of 'if ... else', rather the
assembler-level use of a goto!
Martin, I've bootstrapped this on an x86_64 native setup, but i686
native is tricky. Are you able to give this a spin? I modified the
testcase slightly -- replacing an 'int' with '__SIZE_TYPE__'.
nathan
--
Nathan Sidwell
2018-02-08 Nathan Sidwell <nathan@acm.org>
PR c++/84263
* parser.c (cp_parser_decltype): Push and pop
deferring_access_checks. Reorganize to avoid goto.
* g++.dg/parse/pr84263.C: New.
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 257496)
+++ cp/parser.c (working copy)
@@ -14049,12 +14049,7 @@ cp_parser_decltype_expr (cp_parser *pars
static tree
cp_parser_decltype (cp_parser *parser)
{
- tree expr;
bool id_expression_or_member_access_p = false;
- const char *saved_message;
- bool saved_integral_constant_expression_p;
- bool saved_non_integral_constant_expression_p;
- bool saved_greater_than_is_operator_p;
cp_token *start_token = cp_lexer_peek_token (parser->lexer);
if (start_token->type == CPP_DECLTYPE)
@@ -14073,77 +14068,83 @@ cp_parser_decltype (cp_parser *parser)
if (!parens.require_open (parser))
return error_mark_node;
- /* decltype (auto) */
+ push_deferring_access_checks (dk_deferred);
+
+ tree expr = NULL_TREE;
+
if (cxx_dialect >= cxx14
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
+ /* decltype (auto) */
+ cp_lexer_consume_token (parser->lexer);
+ else
{
- cp_lexer_consume_token (parser->lexer);
- if (!parens.require_close (parser))
- return error_mark_node;
- expr = make_decltype_auto ();
- AUTO_IS_DECLTYPE (expr) = true;
- goto rewrite;
- }
+ /* decltype (expression) */
- /* Types cannot be defined in a `decltype' expression. Save away the
- old message. */
- saved_message = parser->type_definition_forbidden_message;
-
- /* And create the new one. */
- parser->type_definition_forbidden_message
- = G_("types may not be defined in %<decltype%> expressions");
-
- /* The restrictions on constant-expressions do not apply inside
- decltype expressions. */
- saved_integral_constant_expression_p
- = parser->integral_constant_expression_p;
- saved_non_integral_constant_expression_p
- = parser->non_integral_constant_expression_p;
- parser->integral_constant_expression_p = false;
-
- /* Within a parenthesized expression, a `>' token is always
- the greater-than operator. */
- saved_greater_than_is_operator_p
- = parser->greater_than_is_operator_p;
- parser->greater_than_is_operator_p = true;
-
- /* Do not actually evaluate the expression. */
- ++cp_unevaluated_operand;
-
- /* Do not warn about problems with the expression. */
- ++c_inhibit_evaluation_warnings;
-
- expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
-
- /* Go back to evaluating expressions. */
- --cp_unevaluated_operand;
- --c_inhibit_evaluation_warnings;
-
- /* The `>' token might be the end of a template-id or
- template-parameter-list now. */
- parser->greater_than_is_operator_p
- = saved_greater_than_is_operator_p;
-
- /* Restore the old message and the integral constant expression
- flags. */
- parser->type_definition_forbidden_message = saved_message;
- parser->integral_constant_expression_p
- = saved_integral_constant_expression_p;
- parser->non_integral_constant_expression_p
- = saved_non_integral_constant_expression_p;
+ /* Types cannot be defined in a `decltype' expression. Save away the
+ old message and set the new one. */
+ const char *saved_message = parser->type_definition_forbidden_message;
+ parser->type_definition_forbidden_message
+ = G_("types may not be defined in %<decltype%> expressions");
+
+ /* The restrictions on constant-expressions do not apply inside
+ decltype expressions. */
+ bool saved_integral_constant_expression_p
+ = parser->integral_constant_expression_p;
+ bool saved_non_integral_constant_expression_p
+ = parser->non_integral_constant_expression_p;
+ parser->integral_constant_expression_p = false;
+
+ /* Within a parenthesized expression, a `>' token is always
+ the greater-than operator. */
+ bool saved_greater_than_is_operator_p
+ = parser->greater_than_is_operator_p;
+ parser->greater_than_is_operator_p = true;
+
+ /* Do not actually evaluate the expression. */
+ ++cp_unevaluated_operand;
+
+ /* Do not warn about problems with the expression. */
+ ++c_inhibit_evaluation_warnings;
+
+ expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
+
+ /* Go back to evaluating expressions. */
+ --cp_unevaluated_operand;
+ --c_inhibit_evaluation_warnings;
+
+ /* The `>' token might be the end of a template-id or
+ template-parameter-list now. */
+ parser->greater_than_is_operator_p
+ = saved_greater_than_is_operator_p;
+
+ /* Restore the old message and the integral constant expression
+ flags. */
+ parser->type_definition_forbidden_message = saved_message;
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
+ }
/* Parse to the closing `)'. */
if (!parens.require_close (parser))
{
cp_parser_skip_to_closing_parenthesis (parser, true, false,
/*consume_paren=*/true);
+ pop_deferring_access_checks ();
return error_mark_node;
}
- expr = finish_decltype_type (expr, id_expression_or_member_access_p,
- tf_warning_or_error);
+ if (!expr)
+ {
+ /* Build auto. */
+ expr = make_decltype_auto ();
+ AUTO_IS_DECLTYPE (expr) = true;
+ }
+ else
+ expr = finish_decltype_type (expr, id_expression_or_member_access_p,
+ tf_warning_or_error);
- rewrite:
/* Replace the decltype with a CPP_DECLTYPE so we don't need to parse
it again. */
start_token->type = CPP_DECLTYPE;
@@ -14153,6 +14154,8 @@ cp_parser_decltype (cp_parser *parser)
start_token->keyword = RID_MAX;
cp_lexer_purge_tokens_after (parser->lexer, start_token);
+ pop_to_parent_deferring_access_checks ();
+
return expr;
}
Index: testsuite/g++.dg/parse/pr84263.C
===================================================================
--- testsuite/g++.dg/parse/pr84263.C (revision 0)
+++ testsuite/g++.dg/parse/pr84263.C (working copy)
@@ -0,0 +1,36 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "--param ggc-min-expand=0 --param ggc-min-heapsize=0" }
+// PR 84263, a GC bug exposed on i686 native compiler (and possibly
+// other 32-bit hosts). decltype parsing could create a
+// pointer that would be gc-freed by later actions.
+
+namespace std {
+template <typename a> struct b {
+ int c;
+ a d;
+};
+template <typename> class g;
+template <class> class initializer_list {
+ void *e;
+ __SIZE_TYPE__ f;
+};
+class h;
+class j {
+ typedef b<h> i;
+
+public:
+ j();
+ j(initializer_list<i>);
+};
+template <typename> struct m;
+template <int k> struct m<char[k]> {};
+class h {
+public:
+ template <typename l> h(l &);
+};
+class G {
+ G();
+ j n;
+};
+G::G() { n = decltype(n){{0, ""}, {1, ".unoLineArrowEnd"}}; }
+}