[libc-commits] [libc] [libc][hdrgen] Extend guard attribute support for types (PR #191663)

Mohammed Ashraf via libc-commits libc-commits at lists.llvm.org
Sat Apr 11 14:13:01 PDT 2026


https://github.com/Holo-xy updated https://github.com/llvm/llvm-project/pull/191663

>From 5a714a2410fce61a99f7c7825d192cb5bf4d2c31 Mon Sep 17 00:00:00 2001
From: Mohammed Ashraf <mohammedashraf4599 at gmail.com>
Date: Sat, 11 Apr 2026 20:19:01 +0000
Subject: [PATCH 1/2] [libc][hdrgen] Extend guard attribute support for types

Co-authored-by: un-pixelated <masterhc321 at gmail.com>
---
 libc/utils/hdrgen/hdrgen/header.py            | 64 +++++++++++--------
 libc/utils/hdrgen/hdrgen/type.py              |  5 +-
 libc/utils/hdrgen/hdrgen/yaml_to_classes.py   | 16 ++++-
 .../tests/expected_output/func_guarding.h     | 34 ++++++++++
 .../tests/expected_output/type_guarding.h     | 27 ++++++++
 .../hdrgen/tests/input/func_guarding.yaml     | 38 +++++++++++
 .../hdrgen/tests/input/type_guarding.yaml     | 19 ++++++
 libc/utils/hdrgen/tests/test_integration.py   | 14 ++++
 8 files changed, 188 insertions(+), 29 deletions(-)
 create mode 100644 libc/utils/hdrgen/tests/expected_output/func_guarding.h
 create mode 100644 libc/utils/hdrgen/tests/expected_output/type_guarding.h
 create mode 100644 libc/utils/hdrgen/tests/input/func_guarding.yaml
 create mode 100644 libc/utils/hdrgen/tests/input/type_guarding.yaml

diff --git a/libc/utils/hdrgen/hdrgen/header.py b/libc/utils/hdrgen/hdrgen/header.py
index e2ebbdb6e519a..fb97e1129cb1a 100644
--- a/libc/utils/hdrgen/hdrgen/header.py
+++ b/libc/utils/hdrgen/hdrgen/header.py
@@ -175,6 +175,7 @@ def includes(self):
                     PurePosixPath("llvm-libc-types") / f"{typ.name}.h",
                 )
                 for typ in self.all_types()
+                if typ.guard is None
             }
             | {
                 PurePosixPath("llvm-libc-macros") / f"{attr.split('(')[0]}.h"
@@ -239,7 +240,7 @@ def relpath(file):
         # It's implicitly emitted here when using the default template so
         # it can get the right relative path.  Custom template files should
         # all have it explicitly with their right particular relative path.
-        return [
+        content = [
             f"#include {file}"
             for file in ([f'"{relpath(COMMON_HEADER)!s}"'] if with_common else [])
             + sorted(
@@ -248,6 +249,25 @@ def relpath(file):
             )
         ]
 
+        # Add guarded types
+        current_guard = None
+        has_seen_guard = False
+        for typ in sorted(self.types):
+            if typ.guard is None:
+                continue
+            if not has_seen_guard:
+                has_seen_guard = True
+                content.append("")
+            path = COMPILER_HEADER_TYPES.get(
+                typ.name,
+                PurePosixPath("llvm-libc-types") / f"{typ.name}.h",
+            )
+            current_guard = self.__emit_guard(content, current_guard, typ.guard)
+            content.append(f'#include "{relpath(path)!s}"')
+        self.__emit_guard(content, current_guard, None)
+
+        return content
+
     def macro_lines(self):
         content = []
         for macro in sorted(self.macros):
@@ -295,32 +315,13 @@ def public_api(self):
             # elide the blank line between the declarations.
             if last_name == function.name_without_underscores():
                 content.pop()
-            if function.guard == None and current_guard == None:
-                content.append(str(function) + " __NOEXCEPT;")
-                content.append("")
-            else:
-                if current_guard == None:
-                    current_guard = function.guard
-                    content.append(f"#ifdef {current_guard}")
-                    content.append(str(function) + " __NOEXCEPT;")
-                    content.append("")
-                elif current_guard == function.guard:
-                    content.append(str(function) + " __NOEXCEPT;")
-                    content.append("")
-                else:
-                    content.pop()
-                    content.append(f"#endif // {current_guard}")
-                    content.append("")
-                    current_guard = function.guard
-                    if current_guard is not None:
-                        content.append(f"#ifdef {current_guard}")
-                    content.append(str(function) + " __NOEXCEPT;")
-                    content.append("")
-            last_name = function.name_without_underscores()
-        if current_guard != None:
-            content.pop()
-            content.append(f"#endif // {current_guard}")
+            current_guard = self.__emit_guard(
+                content, current_guard, function.guard
+            )
+            content.append(str(function) + " __NOEXCEPT;")
             content.append("")
+            last_name = function.name_without_underscores()
+        self.__emit_guard(content, current_guard, None)
 
         # Emit object declarations.
         content.extend(str(object) for object in self.objects)
@@ -338,3 +339,14 @@ def json_data(self):
             "standards": self.standards,
             "includes": sorted(str(file) for file in {COMMON_HEADER} | self.includes()),
         }
+
+    def __emit_guard(self, content, current_guard, new_guard):
+        if current_guard != new_guard:
+            if current_guard is not None:
+                if content[-1] == "":
+                    content.pop()
+                content.append(f"#endif // {current_guard}")
+                content.append("")
+            if new_guard is not None:
+                content.append(f"#ifdef {new_guard}")
+        return new_guard
diff --git a/libc/utils/hdrgen/hdrgen/type.py b/libc/utils/hdrgen/hdrgen/type.py
index 20c1881a9379a..3a1f3e2eefe93 100644
--- a/libc/utils/hdrgen/hdrgen/type.py
+++ b/libc/utils/hdrgen/hdrgen/type.py
@@ -10,6 +10,7 @@
 
 
 class Type(Symbol):
-    # A type so far carries no specific information beyond its name.
-    def __init__(self, name):
+    # A type carries its name and an optional guard.
+    def __init__(self, name, guard=None):
         super().__init__(name)
+        self.guard = guard
diff --git a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
index 85aa3267b5274..13f75dab60511 100644
--- a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
+++ b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
@@ -52,7 +52,21 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None):
     types = yaml_data.get("types", [])
     sorted_types = sorted(types, key=lambda x: x["type_name"])
     for type_data in sorted_types:
-        header.add_type(Type(type_data["type_name"]))
+        type_name = type_data["type_name"]
+        type_guard = type_data.get("guard")
+        # If a type has a guard, the macro it references must exist in
+        # the same yaml file with a macro_header attribute.
+        if type_guard is not None and not any(
+            macro_data["macro_name"] == type_guard
+            and "macro_header" in macro_data
+            for macro_data in yaml_data.get("macros", [])
+        ):
+            raise ValueError(
+                f"Type '{type_name}' has guard '{type_guard}' but no macro with "
+                f"macro_header '{type_guard}' was found in this file."
+            )
+
+        header.add_type(Type(type_name, type_guard))
 
     for enum_data in yaml_data.get("enums", []):
         header.add_enumeration(
diff --git a/libc/utils/hdrgen/tests/expected_output/func_guarding.h b/libc/utils/hdrgen/tests/expected_output/func_guarding.h
new file mode 100644
index 0000000000000..440710e691d4b
--- /dev/null
+++ b/libc/utils/hdrgen/tests/expected_output/func_guarding.h
@@ -0,0 +1,34 @@
+//===-- Standard C header <func_guarding.h> --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LLVM_LIBC_FUNC_GUARDING_H
+#define _LLVM_LIBC_FUNC_GUARDING_H
+
+#include "__llvm-libc-common.h"
+
+__BEGIN_C_DECLS
+
+#ifdef LIBC_TYPES_HAS_FLOAT128
+void func_all_guarded(int) __NOEXCEPT;
+#endif // LIBC_TYPES_HAS_FLOAT128
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+int func_guarded_a(int) __NOEXCEPT;
+
+int func_guarded_b(int) __NOEXCEPT;
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_TYPES_HAS_FLOAT128
+int func_guarded_c(int) __NOEXCEPT;
+#endif // LIBC_TYPES_HAS_FLOAT128
+
+int func_plain(int) __NOEXCEPT;
+
+__END_C_DECLS
+
+#endif // _LLVM_LIBC_FUNC_GUARDING_H
diff --git a/libc/utils/hdrgen/tests/expected_output/type_guarding.h b/libc/utils/hdrgen/tests/expected_output/type_guarding.h
new file mode 100644
index 0000000000000..33a6fbd22d8d0
--- /dev/null
+++ b/libc/utils/hdrgen/tests/expected_output/type_guarding.h
@@ -0,0 +1,27 @@
+//===-- Standard C header <type_guarding_mixed.h> --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LLVM_LIBC_TYPE_GUARDING_MIXED_H
+#define _LLVM_LIBC_TYPE_GUARDING_MIXED_H
+
+#include "__llvm-libc-common.h"
+#include "llvm-libc-macros/float16-macro.h"
+#include "llvm-libc-macros/size_t-macro.h"
+#include "llvm-libc-types/myType.h"
+#include <stdint.h>
+
+#ifdef LIBC_TYPES_HAS_FLOAT16
+#include "llvm-libc-types/float16.h"
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_TYPES_HAS_SIZE_T
+#include "llvm-libc-types/size_t.h"
+#include "llvm-libc-types/ssize_t.h"
+#endif // LIBC_TYPES_HAS_SIZE_T
+
+#endif // _LLVM_LIBC_TYPE_GUARDING_MIXED_H
diff --git a/libc/utils/hdrgen/tests/input/func_guarding.yaml b/libc/utils/hdrgen/tests/input/func_guarding.yaml
new file mode 100644
index 0000000000000..eb4093d235e17
--- /dev/null
+++ b/libc/utils/hdrgen/tests/input/func_guarding.yaml
@@ -0,0 +1,38 @@
+header: func_guarding.h
+standards:
+  - stdc
+functions:
+  - name: func_plain
+    return_type: int
+    arguments:
+      - type: int
+    standards:
+      - stdc
+  - name: func_guarded_a
+    return_type: int
+    arguments:
+      - type: int
+    standards:
+      - stdc
+    guard: LIBC_TYPES_HAS_FLOAT16
+  - name: func_guarded_b
+    return_type: int
+    arguments:
+      - type: int
+    standards:
+      - stdc
+    guard: LIBC_TYPES_HAS_FLOAT16
+  - name: func_guarded_c
+    return_type: int
+    arguments:
+      - type: int
+    standards:
+      - stdc
+    guard: LIBC_TYPES_HAS_FLOAT128
+  - name: func_all_guarded
+    return_type: void
+    arguments:
+      - type: int
+    standards:
+      - stdc
+    guard: LIBC_TYPES_HAS_FLOAT128
diff --git a/libc/utils/hdrgen/tests/input/type_guarding.yaml b/libc/utils/hdrgen/tests/input/type_guarding.yaml
new file mode 100644
index 0000000000000..b1e7fb14e5d3b
--- /dev/null
+++ b/libc/utils/hdrgen/tests/input/type_guarding.yaml
@@ -0,0 +1,19 @@
+header: type_guarding_mixed.h
+standards:
+  - stdc
+
+macros:
+  - macro_name: LIBC_TYPES_HAS_SIZE_T
+    macro_header: size_t-macro.h
+  - macro_name: LIBC_TYPES_HAS_FLOAT16
+    macro_header: float16-macro.h
+
+types:
+  - type_name: size_t
+    guard: LIBC_TYPES_HAS_SIZE_T
+  - type_name: ssize_t
+    guard: LIBC_TYPES_HAS_SIZE_T
+  - type_name: float16
+    guard: LIBC_TYPES_HAS_FLOAT16
+  - type_name: uint8_t
+  - type_name: myType
diff --git a/libc/utils/hdrgen/tests/test_integration.py b/libc/utils/hdrgen/tests/test_integration.py
index 8848afe29d50f..ef7e158952cfc 100644
--- a/libc/utils/hdrgen/tests/test_integration.py
+++ b/libc/utils/hdrgen/tests/test_integration.py
@@ -96,6 +96,20 @@ def test_generate_macro_only_header(self):
         self.run_script(yaml_file, output_file)
         self.compare_files(output_file, expected_output_file)
 
+    def test_type_guarding(self):
+        yaml_file = self.source_dir / "input/type_guarding.yaml"
+        expected_output_file = self.source_dir / "expected_output/type_guarding.h"
+        output_file = self.output_dir / "type_guarding.h"
+        self.run_script(yaml_file, output_file)
+        self.compare_files(output_file, expected_output_file)
+
+    def test_func_guarding(self):
+        yaml_file = self.source_dir / "input/func_guarding.yaml"
+        expected_output_file = self.source_dir / "expected_output/func_guarding.h"
+        output_file = self.output_dir / "func_guarding.h"
+        self.run_script(yaml_file, output_file)
+        self.compare_files(output_file, expected_output_file)
+
 def main():
     parser = argparse.ArgumentParser(description="TestHeaderGenIntegration arguments")
     parser.add_argument(

>From f11acef2e1296fabf83769a0c998d9276d56ffe0 Mon Sep 17 00:00:00 2001
From: Mohammed Ashraf <mohammedashraf4599 at gmail.com>
Date: Sat, 11 Apr 2026 21:12:26 +0000
Subject: [PATCH 2/2] fix format

---
 libc/utils/hdrgen/hdrgen/header.py          | 4 +---
 libc/utils/hdrgen/hdrgen/yaml_to_classes.py | 3 +--
 libc/utils/hdrgen/tests/test_integration.py | 1 +
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/libc/utils/hdrgen/hdrgen/header.py b/libc/utils/hdrgen/hdrgen/header.py
index fb97e1129cb1a..bc682f614bd35 100644
--- a/libc/utils/hdrgen/hdrgen/header.py
+++ b/libc/utils/hdrgen/hdrgen/header.py
@@ -315,9 +315,7 @@ def public_api(self):
             # elide the blank line between the declarations.
             if last_name == function.name_without_underscores():
                 content.pop()
-            current_guard = self.__emit_guard(
-                content, current_guard, function.guard
-            )
+            current_guard = self.__emit_guard(content, current_guard, function.guard)
             content.append(str(function) + " __NOEXCEPT;")
             content.append("")
             last_name = function.name_without_underscores()
diff --git a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
index 13f75dab60511..068f8cfa408f5 100644
--- a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
+++ b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
@@ -57,8 +57,7 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None):
         # If a type has a guard, the macro it references must exist in
         # the same yaml file with a macro_header attribute.
         if type_guard is not None and not any(
-            macro_data["macro_name"] == type_guard
-            and "macro_header" in macro_data
+            macro_data["macro_name"] == type_guard and "macro_header" in macro_data
             for macro_data in yaml_data.get("macros", [])
         ):
             raise ValueError(
diff --git a/libc/utils/hdrgen/tests/test_integration.py b/libc/utils/hdrgen/tests/test_integration.py
index ef7e158952cfc..31a79e5121040 100644
--- a/libc/utils/hdrgen/tests/test_integration.py
+++ b/libc/utils/hdrgen/tests/test_integration.py
@@ -110,6 +110,7 @@ def test_func_guarding(self):
         self.run_script(yaml_file, output_file)
         self.compare_files(output_file, expected_output_file)
 
+
 def main():
     parser = argparse.ArgumentParser(description="TestHeaderGenIntegration arguments")
     parser.add_argument(



More information about the libc-commits mailing list