https://gcc.gnu.org/g:3bd34f8936c7edb25d35bc2816a863ca902938bf

commit r17-4498-g3bd34f8936c7edb25d35bc2816a863ca902938bf
Author: Joshua Berne <[email protected]>
Date:   Mon Sep 21 00:09:58 2026 +0100

    c++/contracts: fix handling of __contract_assert [PR127295]
    
    PR c++/127295 - [c++26][contracts] ICE in grok_contract on the
    __contract_assert extension spelling
    
    The gcc-specific spelling of contract_assert, __contract_assert, was
    untested and just didn't work.  Changed uses of the raw string
    "contract_assert" to identify the token based on what was parsed (which
    identifies both contract_assert and __contract_assert as a reserved
    identifier with the code RID_CONTASSERT).
    
    Add one use of the alternate spelling in a test, as well as a test of the
    previously untested diagnostic that includes the keyword spelling in its
    output.
    
            PR c++/127295
    
    gcc/cp/ChangeLog:
    
            * contracts.cc (grok_contract): Identify assertion statements
            by keyword and not string comparison.
            * parser.cc (cp_parser_contract_assert): Include keyword used
            on token in diagnostics.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/contracts/cpp26/assertion-statement.C: Add use of
            __contract_assert.
            * g++.dg/contracts/cpp26/assertion-statement-errors.C: Test
            attribute warning with __contract_assert.
            * g++.dg/contracts/cpp26/no_contracts.C: Check keyword errors with
            -fno-contracts.
    
    Signed-off-by: Joshua Berne <[email protected]>

Diff:
---
 gcc/cp/contracts.cc                                          |  3 ++-
 gcc/cp/parser.cc                                             | 12 ++++++------
 .../g++.dg/contracts/cpp26/assertion-statement-errors.C      |  1 +
 gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C   |  2 ++
 gcc/testsuite/g++.dg/contracts/cpp26/no_contracts.C          |  7 +++++++
 5 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index cca568fa343c..f509424fd7c0 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -2083,7 +2083,8 @@ grok_contract (tree contract_spec, tree mode, tree 
result, cp_expr condition,
 
   tree_code code;
   contract_assertion_kind kind = CAK_INVALID;
-  if (id_equal (contract_spec, "contract_assert"))
+  if (IDENTIFIER_KEYWORD_P (contract_spec)
+      && C_RID_CODE (contract_spec) == RID_CONTASSERT)
     {
       code = ASSERTION_STMT;
       kind = CAK_ASSERT;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 720dec6841eb..9c4245bc3f5e 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -33897,16 +33897,16 @@ cp_parser_late_contracts (cp_parser *parser, tree 
fndecl)
 static tree
 cp_parser_contract_assert (cp_parser *parser, cp_token *token)
 {
+  tree cont_assert = token->u.value;
+
   if (!flag_contracts)
     {
-      error_at (token->location, "%qs is only available with %qs",
-               "contract_assert", "-fcontracts");
+      error_at (token->location, "%qE is only available with %qs",
+               cont_assert, "-fcontracts");
       cp_parser_skip_to_end_of_statement (parser);
       return error_mark_node;
     }
 
-  tree cont_assert = token->u.value;
-
   token = cp_lexer_consume_token (parser->lexer);
   location_t loc = token->location;
 
@@ -33915,8 +33915,8 @@ cp_parser_contract_assert (cp_parser *parser, cp_token 
*token)
   if (std_attrs)
     {
       attrs_loc = make_location (attrs_loc, attrs_loc, input_location);
-      warning_at (attrs_loc, OPT_Wattributes, "attributes are ignored on %qs",
-                 "contract_assert");
+      warning_at (attrs_loc, OPT_Wattributes, "attributes are ignored on %qE",
+                 cont_assert);
       std_attrs = NULL_TREE;
     }
 
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement-errors.C 
b/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement-errors.C
index ef711368404f..32204cbf8caf 100644
--- a/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement-errors.C
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement-errors.C
@@ -36,6 +36,7 @@ int main()
     g();
 
     contract_assert [[deprecated]] (i == 3);  // { dg-warning {attributes are 
ignored on 'contract_assert'} }
+    __contract_assert [[deprecated]] (i == 3);  // { dg-warning {attributes 
are ignored on '__contract_assert'} }
 
     return 0;
 }
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C 
b/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C
index c4ec7f887214..d2d089ac1361 100644
--- a/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/assertion-statement.C
@@ -11,6 +11,8 @@ int main()
 {
   int x;
 
+  __contract_assert( x >= 0);
+
   contract_assert( x >= 0);
   contract_assert( x < 0);
   contract_assert( x == 0);
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/no_contracts.C 
b/gcc/testsuite/g++.dg/contracts/cpp26/no_contracts.C
new file mode 100644
index 000000000000..2162b8e05b95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/no_contracts.C
@@ -0,0 +1,7 @@
+// { dg-options "-fno-contracts -std=c++26" }
+
+void f()
+{
+    contract_assert(false); // { dg-error "'contract_assert' is only available 
with '-fcontracts'" }
+    __contract_assert(false); // { dg-error "'__contract_assert' is only 
available with '-fcontracts'" }
+}

Reply via email to