From 11b1d6a1421e7b80a9dd51fa7505b114f388a9d9 Mon Sep 17 00:00:00 2001
From: Andre Maroneze <andre.maroneze@cea.fr>
Date: Fri, 17 May 2024 13:15:11 +0200
Subject: [PATCH] [Kernel] allow _Pragma in function signature (as does GCC)

---
 src/kernel_internals/parsing/cparser.mly      | 12 +++++++-
 .../plugin_entry_points/kernel.ml             |  2 ++
 .../plugin_entry_points/kernel.mli            |  3 ++
 tests/misc/oracle/audit-out.json              |  5 ++--
 .../syntax/oracle/pragma_operator.res.oracle  | 30 +++++++++++++++++++
 tests/syntax/pragma_operator.c                | 13 ++++++++
 6 files changed, 62 insertions(+), 3 deletions(-)
 create mode 100644 tests/syntax/oracle/pragma_operator.res.oracle
 create mode 100644 tests/syntax/pragma_operator.c

diff --git a/src/kernel_internals/parsing/cparser.mly b/src/kernel_internals/parsing/cparser.mly
index 9da7b7b8aa9..414df24d404 100644
--- a/src/kernel_internals/parsing/cparser.mly
+++ b/src/kernel_internals/parsing/cparser.mly
@@ -1190,7 +1190,17 @@ decl_spec_wo_type:                         /* ISO 6.7 */
 
 decl_spec_list:
 | decl_spec_wo_type decl_spec_list_opt { fst $1 :: $2, snd $1 }
-| type_spec decl_spec_list_opt_no_named { SpecType(fst $1) :: $2, snd $1 }
+| type_spec pragma* (* pragma accepted by GCC *) decl_spec_list_opt_no_named
+  {
+    let pragmas = $2 in
+    if pragmas != [] then begin
+      let loc = Cabshelper.get_definitionloc (List.hd pragmas) in
+      Kernel.warning ~wkey:Kernel.wkey_parser_unsupported_pragma
+        ~once:true ~source:(fst loc)
+        "Discarding _Pragma's in function declaration"
+    end;
+    SpecType(fst $1) :: $3, snd $1
+  }
 
 decl_spec_list_no_named:
 | decl_spec_wo_type decl_spec_list_opt_no_named { fst $1 :: $2, snd $1 }
diff --git a/src/kernel_services/plugin_entry_points/kernel.ml b/src/kernel_services/plugin_entry_points/kernel.ml
index 86bb74a82b3..d4fff3d5b98 100644
--- a/src/kernel_services/plugin_entry_points/kernel.ml
+++ b/src/kernel_services/plugin_entry_points/kernel.ml
@@ -223,6 +223,8 @@ let wkey_parser_unsupported = register_warn_category "parser:unsupported"
 
 let wkey_parser_unsupported_attributes = register_warn_category "parser:unsupported:attributes"
 
+let wkey_parser_unsupported_pragma = register_warn_category "parser:unsupported:pragma"
+
 let wkey_asm = register_warn_category "asm:clobber"
 
 let wkey_unnamed_typedef = register_warn_category "parser:unnamed-typedef"
diff --git a/src/kernel_services/plugin_entry_points/kernel.mli b/src/kernel_services/plugin_entry_points/kernel.mli
index 940ff68224f..13e35743a12 100644
--- a/src/kernel_services/plugin_entry_points/kernel.mli
+++ b/src/kernel_services/plugin_entry_points/kernel.mli
@@ -220,6 +220,9 @@ val wkey_parser_unsupported: warn_category
 val wkey_parser_unsupported_attributes: warn_category
 (** Warning related to unsupported attributes during parsing. *)
 
+val wkey_parser_unsupported_pragma: warn_category
+(** Warning related to unsupported _Pragma's during parsing. *)
+
 val wkey_asm: warn_category
 (** Warnings related to assembly code. *)
 
diff --git a/tests/misc/oracle/audit-out.json b/tests/misc/oracle/audit-out.json
index da80b2ca653..0307758ad62 100644
--- a/tests/misc/oracle/audit-out.json
+++ b/tests/misc/oracle/audit-out.json
@@ -62,8 +62,9 @@
         "linker:drop-conflicting-unused", "linker:weak", "parser",
         "parser:conditional-feature", "parser:unnamed-typedef",
         "parser:unsupported", "parser:unsupported:attributes",
-        "plugin-not-loaded", "pp", "pp:compilation-db", "pp:line-directive",
-        "too-large-array", "typing", "typing:implicit-conv-void-ptr",
+        "parser:unsupported:pragma", "plugin-not-loaded", "pp",
+        "pp:compilation-db", "pp:line-directive", "too-large-array",
+        "typing", "typing:implicit-conv-void-ptr",
         "typing:implicit-function-declaration",
         "typing:incompatible-pointer-types",
         "typing:incompatible-types-call", "typing:inconsistent-specifier",
diff --git a/tests/syntax/oracle/pragma_operator.res.oracle b/tests/syntax/oracle/pragma_operator.res.oracle
new file mode 100644
index 00000000000..9dfdd735b25
--- /dev/null
+++ b/tests/syntax/oracle/pragma_operator.res.oracle
@@ -0,0 +1,30 @@
+[kernel] Parsing pragma_operator.c (with preprocessing)
+[kernel:parser:unsupported:pragma] pragma_operator.c:3: Warning: 
+  Discarding _Pragma's in function declaration
+[kernel:parser:unsupported:pragma] pragma_operator.c:7: Warning: 
+  Discarding _Pragma's in function declaration
+[kernel:parser:unsupported:pragma] pragma_operator.c:9: Warning: 
+  Discarding _Pragma's in function declaration
+[kernel:parser:unsupported:pragma] pragma_operator.c:12: Warning: 
+  Discarding _Pragma's in function declaration
+/* Generated by Frama-C */
+int main(void)
+{
+  int __retres;
+  __retres = 0;
+  return __retres;
+}
+
+void main2(void);
+
+void main2(void)
+{
+  return;
+}
+
+void main3(void)
+{
+  return;
+}
+
+
diff --git a/tests/syntax/pragma_operator.c b/tests/syntax/pragma_operator.c
new file mode 100644
index 00000000000..93742b107c9
--- /dev/null
+++ b/tests/syntax/pragma_operator.c
@@ -0,0 +1,13 @@
+// The pragma below is allowed by GCC (14), but only on a .c file.
+// Clang (18) also accepts it on a .i file.
+int _Pragma("entrypoint") main( void) {
+    return 0;
+}
+
+void _Pragma("entrypoint") main2();
+
+void _Pragma("entrypoint") main2() {
+}
+
+void _Pragma("entrypoint") _Pragma("another pragma") _Pragma("") main3() {
+}
-- 
GitLab