Certain places in contract parsing currently do not check for errors.
This results in contracts
with embedded errors which eventually confuse gimplify. Checks for
errors added in
grok_contract() and cp_parser_contract_attribute_spec() to exit early
if an error is encountered.

Tested on x86_64-pc-linux-gnu
---

        PR c++/113968

gcc/cp/ChangeLog:

        * contracts.cc (grok_contract): Check for error_mark_node early
          exit
        * parser.cc (cp_parser_contract_attribute_spec): Check for
          error_mark_node early exit

gcc/testsuite/ChangeLog:

        * g++.dg/contracts/pr113968.C: New test.

Signed-off-by: Nina Ranns <dinka.ra...@gmail.com>


---
 gcc/cp/contracts.cc                       |  7 ++++++
 gcc/cp/parser.cc                          |  3 +++
 gcc/testsuite/g++.dg/contracts/pr113968.C | 29 +++++++++++++++++++++++
 3 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/contracts/pr113968.C

diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index 634e3cf4fa9..a7d0fdacf6e 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -750,6 +750,9 @@ tree
 grok_contract (tree attribute, tree mode, tree result, cp_expr condition,
            location_t loc)
 {
+  if (condition == error_mark_node)
+    return error_mark_node;
+
   tree_code code;
   if (is_attribute_p ("assert", attribute))
     code = ASSERTION_STMT;
@@ -785,6 +788,10 @@ grok_contract (tree attribute, tree mode, tree
result, cp_expr condition,

   /* The condition is converted to bool.  */
   condition = finish_contract_condition (condition);
+
+  if (condition == error_mark_node)
+    return error_mark_node;
+
   CONTRACT_CONDITION (contract) = condition;

   return contract;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 31ae9c2fb54..22c5e760aee 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -30835,6 +30835,9 @@ cp_parser_contract_attribute_spec (cp_parser
*parser, tree attribute)
       return error_mark_node;
     }

+  if (contract == error_mark_node)
+    return error_mark_node;
+
   return finish_contract_attribute (attribute, contract);
 }

diff --git a/gcc/testsuite/g++.dg/contracts/pr113968.C
b/gcc/testsuite/g++.dg/contracts/pr113968.C
new file mode 100644
index 00000000000..fbaad1c930d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/pr113968.C
@@ -0,0 +1,29 @@
+// check that an invalid contract condition doesn't cause an ICE
+// { dg-do compile }
+// { dg-options "-std=c++2a -fcontracts " }
+
+struct A
+{
+  A (A&);
+};
+struct S
+{
+  void f(A a)
+    [[ pre : a]] // { dg-error "could not convert" }
+    [[ pre : a.b]]// { dg-error "has no member" }
+    {
+
+    }
+};
+void f(A a)
+  [[ pre : a]] // { dg-error "could not convert" }
+  [[ pre : a.b]]// { dg-error "has no member" }
+  {
+    [[ assert : a ]]; // { dg-error "could not convert" }
+    [[ assert : a.b ]];// { dg-error "has no member" }
+  }
+
+int
+main ()
+{
+}
-- 
2.45.2

Reply via email to