From: Owen Avery <[email protected]>

"active" features can be "incomplete" and declare_features can invoke
itself with __status_to_bool.

gcc/rust/ChangeLog:

        * checks/errors/feature/contrib/Makefile: Remove copyright year
        templating.
        * checks/errors/feature/contrib/copyright-stub.h: Fill in
        copyright year.
        * checks/errors/feature/contrib/parse.y: Handle incomplete and
        __status_to_bool.
        * checks/errors/feature/contrib/scan.l: Likewise and improve
        string literal escape handling.

Signed-off-by: Owen Avery <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/7a19dd777450d4dd8b6156e66addc943d4c13195

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4936

 .../checks/errors/feature/contrib/Makefile    |  3 +-
 .../errors/feature/contrib/copyright-stub.h   |  2 +-
 .../checks/errors/feature/contrib/parse.y     | 30 ++++++++++----
 gcc/rust/checks/errors/feature/contrib/scan.l | 40 ++++++++++++++++++-
 4 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/gcc/rust/checks/errors/feature/contrib/Makefile 
b/gcc/rust/checks/errors/feature/contrib/Makefile
index 036236166..15344e171 100644
--- a/gcc/rust/checks/errors/feature/contrib/Makefile
+++ b/gcc/rust/checks/errors/feature/contrib/Makefile
@@ -45,8 +45,7 @@ build/download.rs: fetch
 $(OUT): build/feature-extract build/download.rs
        # add copyright header + newline
        echo | \
-           cat copyright-stub.h - | \
-           sed "s/YYYY/$$(date +%Y)/" > build/rust-feature-defs.h
+           cat copyright-stub.h - > build/rust-feature-defs.h
        cat build/download.rs | ./$< >> build/rust-feature-defs.h
        clang-format -i build/rust-feature-defs.h \
            --style=file:../../../../../../contrib/clang-format
diff --git a/gcc/rust/checks/errors/feature/contrib/copyright-stub.h 
b/gcc/rust/checks/errors/feature/contrib/copyright-stub.h
index 662bad37b..9164dc944 100644
--- a/gcc/rust/checks/errors/feature/contrib/copyright-stub.h
+++ b/gcc/rust/checks/errors/feature/contrib/copyright-stub.h
@@ -1,4 +1,4 @@
-// Copyright (C) YYYY Free Software Foundation, Inc.
+// Copyright (C) 2025-2026 Free Software Foundation, Inc.
 
 // This file is part of GCC.
 
diff --git a/gcc/rust/checks/errors/feature/contrib/parse.y 
b/gcc/rust/checks/errors/feature/contrib/parse.y
index 175721f4b..02d9e38f4 100644
--- a/gcc/rust/checks/errors/feature/contrib/parse.y
+++ b/gcc/rust/checks/errors/feature/contrib/parse.y
@@ -40,7 +40,7 @@ void yyerror (char const *);
 %token <str> IDENT STR NUM
 %token SCOPE
 %token K_SOME K_NONE
-%token K_ACTIVE K_ACCEPTED K_REMOVED K_STABLE_REMOVED
+%token K_ACTIVE K_INCOMPLETE K_STATUS_TO_BOOL K_ACCEPTED K_REMOVED 
K_STABLE_REMOVED
 %token K_E_START K_E_2018
 
 %type <str> issue
@@ -55,11 +55,11 @@ multi_database: multi_database database
 
 database: '(' entry_list ')';
 
-entry_list: entry_list entry ','
-| entry ','
+entry_list: entry_list entry
+| entry
 ;
 
-entry: '(' K_ACTIVE ',' IDENT ',' STR ',' issue ',' edition ')' {
+entry: '(' K_ACTIVE ',' IDENT ',' STR ',' issue ',' edition ')' ',' {
   char *ident_upper = strdup ($4);
   for (size_t i = 0; ident_upper[i]; i++)
     ident_upper[i] = toupper (ident_upper[i]);
@@ -69,7 +69,18 @@ entry: '(' K_ACTIVE ',' IDENT ',' STR ',' issue ',' edition 
')' {
   free ($6);
   free ($8);
 }
-| '(' K_ACCEPTED ',' IDENT ',' STR ',' issue ',' K_NONE ')' {
+| '(' K_INCOMPLETE ',' IDENT ',' STR ',' issue ',' edition ')' ',' {
+  char *ident_upper = strdup ($4);
+  for (size_t i = 0; ident_upper[i]; i++)
+    ident_upper[i] = toupper (ident_upper[i]);
+  // TODO: pass incomplete flag to C++?
+  printf ("FEATURE_ACTIVE (\"%s\", %s, %s, %s%s%s, EDITION_%s)\n", $4, 
ident_upper, $6, UNWRAP_OPT_STR ("ISSUE", $8), $10 ? $10 : "NONE");
+  free ($4);
+  free (ident_upper);
+  free ($6);
+  free ($8);
+}
+| '(' K_ACCEPTED ',' IDENT ',' STR ',' issue ',' K_NONE ')' ',' {
   char *ident_upper = strdup ($4);
   for (size_t i = 0; ident_upper[i]; i++)
     ident_upper[i] = toupper (ident_upper[i]);
@@ -79,7 +90,7 @@ entry: '(' K_ACTIVE ',' IDENT ',' STR ',' issue ',' edition 
')' {
   free ($6);
   free ($8);
 }
-| '(' K_REMOVED ',' IDENT ',' STR ',' issue ',' K_NONE ',' reason ')' {
+| '(' K_REMOVED ',' IDENT ',' STR ',' issue ',' K_NONE ',' reason ')' ',' {
   char *ident_upper;
   // HACK: convert no_debug to F_NO_DEBUG instead
   // since NO_DEBUG is used as an unrelated macro
@@ -100,7 +111,7 @@ entry: '(' K_ACTIVE ',' IDENT ',' STR ',' issue ',' edition 
')' {
   free ($8);
   free ($12);
 }
-| '(' K_STABLE_REMOVED ',' IDENT ',' STR ',' issue ',' K_NONE ')' {
+| '(' K_STABLE_REMOVED ',' IDENT ',' STR ',' issue ',' K_NONE ')' ',' {
   char *ident_upper = strdup ($4);
   for (size_t i = 0; ident_upper[i]; i++)
     ident_upper[i] = toupper (ident_upper[i]);
@@ -110,6 +121,11 @@ entry: '(' K_ACTIVE ',' IDENT ',' STR ',' issue ',' 
edition ')' {
   free ($6);
   free ($8);
 }
+| K_STATUS_TO_BOOL IDENT {
+  // no-op
+  // declare_features! sometimes invokes itself
+  // false positive
+}
 ;
 
 issue: K_SOME '(' NUM ')' { $$ = $3; }
diff --git a/gcc/rust/checks/errors/feature/contrib/scan.l 
b/gcc/rust/checks/errors/feature/contrib/scan.l
index e2778b63b..4c3ba0bcf 100644
--- a/gcc/rust/checks/errors/feature/contrib/scan.l
+++ b/gcc/rust/checks/errors/feature/contrib/scan.l
@@ -22,6 +22,40 @@ along with GCC; see the file COPYING3.  If not see
 
 static int p_count = 0;
 
+static void expand_char_lit (char *contents)
+{
+  // can not consume more space than original
+  // only expand \\\n[ws]* -> ""
+  // since everything else should be handled by C++
+  char *read = contents;
+  char *write = contents;
+  while (*read)
+    {
+      if (read[0] == '\\' && read[1] == '\n')
+       {
+         read += 2;
+         while (1)
+           {
+             switch (*read)
+               {
+               case '\t':
+               case '\n':
+               case '\r':
+               case ' ':
+                 read++;
+                 continue;
+               }
+             break;
+           }
+       }
+      else
+        {
+         *(write++) = *(read++);
+       }
+    }
+  *write = '\0';
+}
+
 %}
 
 %x INSIDE COMMENT
@@ -38,15 +72,17 @@ declare_features!           BEGIN (INSIDE);
 <INSIDE>Some                   return K_SOME;
 <INSIDE>None                   return K_NONE;
 <INSIDE>active                 return K_ACTIVE;
+<INSIDE>incomplete             return K_INCOMPLETE;
 <INSIDE>accepted               return K_ACCEPTED;
 <INSIDE>removed                        return K_REMOVED;
 <INSIDE>stable_removed         return K_STABLE_REMOVED;
 <INSIDE>Edition                        return K_E_START;
 <INSIDE>Edition2018            return K_E_2018;
+<INSIDE>__status_to_bool       return K_STATUS_TO_BOOL;
 
-<INSIDE>[A-Za-z_][A-Za-z0-9_]* yylval.str = strdup (yytext); return IDENT;
+<INSIDE>$?[A-Za-z_][A-Za-z0-9_]*       yylval.str = strdup (yytext); return 
IDENT;
 <INSIDE>[1-9][0-9]*            yylval.str = strdup (yytext); return NUM;
-<INSIDE>\"[^"]+\"              yylval.str = strdup (yytext); return STR;
+<INSIDE>\"([^"\\]|\\\"|\\\n)*\"        yylval.str = strdup (yytext); 
expand_char_lit (yylval.str); return STR;
 <INSIDE>"/""/"                 BEGIN (COMMENT);
 <INSIDE>[ \n]                  /* ignore */
 <INSIDE>.                      { fprintf (stderr, "unrecognized character 
%u\n", (unsigned int) yytext[0]); exit (1); }

base-commit: accca202ed122cb1e1af1988c144f9a889ee9103
-- 
2.55.0

Reply via email to