[PR c++/84263] GC ICE with decltype
authorNathan Sidwell <nathan@acm.org>
Mon, 12 Feb 2018 11:58:40 +0000 (11:58 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Mon, 12 Feb 2018 11:58:40 +0000 (11:58 +0000)
https://gcc.gnu.org/ml/gcc-patches/2018-02/msg00435.html
PR c++/84263
* parser.c (cp_parser_decltype): Push and pop
deferring_access_checks.  Reorganize to avoid goto.

* g++.dg/parse/pr84263.C: New.

From-SVN: r257584

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/pr84263.C [new file with mode: 0644]

index bb7e9173072456bbdec018fee94e05aebdb9241c..2f12a35a1b536483b5c431483002791c38bfcab0 100644 (file)
@@ -1,3 +1,9 @@
+2018-02-12  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/84263
+       * parser.c (cp_parser_decltype): Push and pop
+       deferring_access_checks.  Reorganize to avoid goto.
+
 2018-02-12  Richard Biener  <rguenther@suse.de>
 
        PR c++/84281
index ac5277db9ad250ca76c010ddfd66cc16d0ed12ae..e1e8741d21de84ede76be197f3a99e7348a9e777 100644 (file)
@@ -14049,12 +14049,7 @@ cp_parser_decltype_expr (cp_parser *parser,
 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;
-    }
-
-  /* Types cannot be defined in a `decltype' expression.  Save away the
-     old message.  */
-  saved_message = parser->type_definition_forbidden_message;
+      /* decltype (expression)  */
 
-  /* And create the new one.  */
-  parser->type_definition_forbidden_message
-    = G_("types may not be defined in %<decltype%> expressions");
+      /* 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.  */
-  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;
+      /* 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.  */
-  saved_greater_than_is_operator_p
-    = parser->greater_than_is_operator_p;
-  parser->greater_than_is_operator_p = true;
+      /* 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 actually evaluate the expression.  */
+      ++cp_unevaluated_operand;
 
-  /* Do not warn about problems with the expression.  */
-  ++c_inhibit_evaluation_warnings;
+      /* Do not warn about problems with the expression.  */
+      ++c_inhibit_evaluation_warnings;
 
-  expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
+      expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
 
-  /* Go back to evaluating expressions.  */
-  --cp_unevaluated_operand;
-  --c_inhibit_evaluation_warnings;
+      /* 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;
+      /* 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;
+      /* 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 d11609de5ef256089b25ef9d16ddee5ff2fe0acc..677fed9da3f419d7b62c7e053cc915ed1823dbfa 100644 (file)
@@ -1,3 +1,7 @@
+2018-02-12  Nathan Sidwell  <nathan@acm.org>
+
+       * g++.dg/parse/pr84263.C: New.
+
 2018-02-12  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/79626
diff --git a/gcc/testsuite/g++.dg/parse/pr84263.C b/gcc/testsuite/g++.dg/parse/pr84263.C
new file mode 100644 (file)
index 0000000..e492d8c
--- /dev/null
@@ -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"}}; }
+}