[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